首页 / Pandas 入门教程 / 聚合:agg 与命名聚合

Pandas 入门教程

聚合:agg 与命名聚合

本教程共 54 篇 · 第 38 篇 · 更新于 2026-08-11 · 约 5 分钟阅读

PandasPandas 入门教程agg聚合命名聚合NamedAgg

本节目标:用 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_indexrename 整理。

不想要函数名做列名,可以用”新列名 + 函数”的元组列表:

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 慢几十倍。