聚合:agg 与命名聚合
本教程共 54 篇 · 第 38 篇 · 更新于 2026-08-11 · 约 5 分钟阅读
本节目标:用 agg 对每个分组做单函数、多函数、按列不同函数的聚合,并用命名聚合给结果起一个清楚的名字。
聚合(aggregation)是分组分析里用得最多的一步:每组算出一个或几个汇总值,组数变成了行数。§37 见过的 sum、mean 就是聚合。这一章系统讲 agg。
agg:一个入口,多种玩法
分组对象上可以直接调 .sum()、.mean(),但更灵活的是 agg。agg 接受字符串、函数、列表、字典,几乎覆盖所有聚合需求。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售", "技术"],
"姓名": ["张三", "李四", "王五", "赵六", "钱七", "孙八"],
"薪资": [12000, 15000, 11000, 18000, 14000, 13000],
"奖金": [2000, 3000, 1000, 5000, 2500, 1800],
})
grouped = df.groupby("部门")
单函数聚合
传字符串,等价于调用同名方法:
grouped["薪资"].agg("sum") # 等价 grouped["薪资"].sum()
grouped[["薪资", "奖金"]].agg("mean") # 等价 grouped[["薪资", "奖金"]].mean()
pandas 内置的聚合方法大多能这样传:sum、mean、median、min、max、count、size、nunique、std、var、first、last、quantile。注意先选列再聚合:grouped[["薪资", "奖金"]] 只算数值列,混着文本列(比如”姓名”)直接聚合会报错或得到奇怪结果。
带参数的聚合直接调用方法即可:
grouped["薪资"].quantile(0.9) # 组内 90 分位
多函数聚合:列表
想一次算总和、平均、标准差,传一个列表:
grouped["薪资"].agg(["sum", "mean", "std"])
结果是一个 DataFrame,列名自动用函数名。对多列同时聚合也一样:
grouped[["薪资", "奖金"]].agg(["sum", "mean"])
列名变成两层(薪资、奖金 × sum、mean),后续可以用 reset_index 或 rename 整理。
不想要函数名做列名,可以用”新列名 + 函数”的元组列表:
grouped["薪资"].agg([("总和", "sum"), ("平均", "mean")])
不同列不同函数:字典
传字典,键是列名,值是对该列的聚合:
grouped.agg({"薪资": "sum", "奖金": "mean"})
也可以混入自定义函数:
grouped.agg({"薪资": "sum", "奖金": lambda x: x.max() - x.min()})
Warning用自定义函数(UDF)聚合比内置方法慢得多,大数据集上可能差几十倍。能拆成内置方法链的,就别写 lambda。
自定义聚合函数
内置函数不够用时,自己写函数:它接收一个 Series(组内某一列),返回一个标量:
def 极差(x):
return x.max() - x.min()
grouped["薪资"].agg(极差)
返回集合、返回其他类型都行,pandas 会尽量推断结果的 dtype。写自定义函数时不要修改传入的 Series,pandas 不保证改动生效。
命名聚合:输出列名自己做主
前面的写法列名要么是函数名,要么不好读。命名聚合(named aggregation)专门解决这个问题:关键字是输出列名,值是 (列, 函数) 元组:
grouped.agg(
最低薪资=("薪资", "min"),
最高薪资=("薪资", "max"),
平均奖金=("奖金", "mean"),
)
结果一目了然。也可以写成 pd.NamedAgg:
grouped.agg(
最低薪资=pd.NamedAgg(column="薪资", aggfunc="min"),
)
NamedAgg 只是带字段名的元组,两种写法等价,选顺手的。
Tip要长期维护的代码,优先用命名聚合:输出列名、来源列、聚合函数写在一行,别人(包括三个月后的你)一眼看懂。
对单个列做命名聚合,值直接写函数名:
grouped["薪资"].agg(最低="min", 最高="max")
聚合完想改列名,也可以用 rename 链式处理:
(grouped["薪资"].agg(["sum", "mean"])
.rename(columns={"sum": "总和", "mean": "平均"}))
内置聚合方法速查
| 方法 | 作用 |
|---|---|
| sum / mean / median | 求和、平均、中位数 |
| min / max | 最小、最大 |
| count | 非缺失值个数 |
| size | 行数(含缺失) |
| nunique | 去重后个数 |
| std / var | 标准差、方差 |
| first / last | 组内第一个 / 最后一个非缺失值 |
| quantile(q=0.5) | 分位数 |
| describe | 一组汇总统计(不是聚合,但很有用) |
describe 不用 agg,分组后直接调用:
grouped[["薪资"]].describe()
每组输出 count、mean、std、min、25%、50%、75%、max,做初步探索非常方便。
as_index:分组键放哪
默认分组键成为结果索引;想要普通列,在 groupby 时传 as_index=False:
df.groupby("部门", as_index=False).agg({"薪资": "sum"})
Note
as_index是 groupby 的参数,不是 agg 的。已经聚合出 MultiIndex 结果时,也可以用reset_index()把分组键变回列,效果一样,只是多一次复制。
小结
agg 一个入口四种玩法:字符串、函数、列表、字典,覆盖从”单函数”到”不同列不同函数”的全部聚合需求。命名聚合(关键字 = (列, 函数))让输出列名自己做主,长期维护的代码优先用它。内置方法够用就别写自定义函数,UDF 慢几十倍。