groupby.agg()传字典时键必须严格匹配列名,值须为字符串、函数或lambda;单层字典不重命名列,需用元组列表(如{'a': [('a_sum', 'sum')]})或嵌套字典(如{'c': {'c_min': 'min'}})实现自定义列名与展平输出。

groupby.agg() 传字典时键必须是列名,值必须是可调用对象或字符串
直接传 {'A': 'sum', 'B': np.mean} 是最常见写法,但容易踩坑:键名必须严格匹配原始 DataFrame 的列名(区分大小写、空格),不能是位置索引;值可以是字符串(如 'max')、函数(如 np.std)、lambda(如 lambda x: x.nunique()),但不能是带括号的调用结果(比如写成 np.sum() 就会立刻报错 TypeError: 'numpy.float64' object is not callable)。
常见错误现象:KeyError: 'column_name' —— 实际列名可能是 'column_name '(尾部空格)或 'Column_Name';或者用了 df.groupby('x').agg({'y': 'sum'}).columns 却发现返回的是 Index(['y']),而非预期的多级列——这是因为单层字典映射不会触发列名重命名,只有传入列表或嵌套元组才会。
- 检查列名用
df.columns.tolist(),别靠肉眼数空格 - 若需对同一列应用多个函数,得改用元组形式:
{'A': [('sum_A', 'sum'), ('mean_A', 'mean')]} - 字符串函数名必须是 pandas 内置支持的,比如
'nunique'可以,'count_distinct'就不行
想保留原始列名并添加后缀?得用命名元组,不能只靠字典
纯字典映射(如 {'A': 'sum', 'B': 'mean'})输出的列名就是原始列名,没有任何标识说明做了什么聚合。如果要生成 A_sum、B_mean 这样的新列名,必须把值写成含名字的元组序列,例如:{'A': [('A_sum', 'sum')], 'B': [('B_mean', 'mean')]}。注意这里每个值都是**列表**,里面包着一个或多个 (新列名, 聚合操作) 元组。
使用场景:导出报表、拼接多个 groupby 结果、避免后续 merge 时列名冲突。性能上无差异,但可读性提升明显;兼容性方面,该写法从 pandas 0.25+ 完全支持,老版本会报 ValueError: nested renamer is not supported。
- 漏掉外层列表(如写成
{'A': ('A_sum', 'sum')})会导致TypeError: unhashable type: 'tuple' - 元组里第一个元素是字符串,第二个是字符串或函数,顺序不能反
- 若某列只想保留原名,又想加后缀,只能显式重命名:
.rename(columns={'A': 'A_sum'})
对一列同时做多个聚合,且不想用 MultiIndex 列?用字典套字典
当需要对列 C 同时算 min 和 max,又希望结果是平铺的普通列(C_min、C_max),而不是二级列((C, min)、(C, max)),就不能用 ['min', 'max'] 这种列表写法(它默认产生 MultiIndex)。正确做法是用嵌套字典:{'C': {'C_min': 'min', 'C_max': 'max'}}。这种结构会被 pandas 自动展平,输出列名为 C_min、C_max。
这个语法容易被忽略,因为文档里藏得深,且和前面的元组写法风格不一致。但它在构建宽表、对接 BI 工具时非常实用——避免后续还要用 df.columns.map('_'.join) 手动拍平。
- 嵌套字典的内层键(如
'C_min')必须是字符串,不能是变量名或表达式 - 外层键(
'C')仍需与原始列名完全一致 - 混合使用时要注意层级:字典套字典 + 元组列表不能混在同一层,否则解析失败
自定义函数传参太麻烦?用 functools.partial 或 lambda 封装
如果聚合函数需要固定参数(比如 np.quantile(x, q=0.9)),直接往字典里写 np.quantile 不行,因为缺少 q。这时候要么用 functools.partial(np.quantile, q=0.9),要么用 lambda x: np.quantile(x, q=0.9)。两者效果一样,但 partial 更适合复用,lambda 更直观。
容易踩的坑是闭包变量捕获错误:比如循环中写 for q in [0.1, 0.9]: aggs[f'p{int(q*100)}'] = lambda x: np.quantile(x, q=q),最后两个 key 都会用 q=0.9——因为 lambda 捕获的是变量引用,不是值。解决方法是加默认参数绑定:lambda x, q=q: np.quantile(x, q=q)。
- 不要在 lambda 里调用
.item()或float()强转,groupby 传入的是 Series,不是标量 - 自定义函数返回值必须能被 pandas 拼接,比如返回
pd.Series会自动对齐索引,返回标量更安全 - 调试时可在函数里加
print(type(x), len(x))确认输入确实是分组后的 Series
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











