跳到主要内容

数据分组

groupby 的核心逻辑是 Split-Apply-Combine:按一个或多个键将行拆分,对每个分区执行操作,最后合并结果。动手前,先想清楚你要什么形状的输出来。

按输出形状选择方法

方法输出特征
agg标量汇总时每组一行
transform返回与原始行对齐的值(行数不变)
filter保留或剔除整个组(行可能减少)
apply输出灵活;仅当上述方法都不适用时使用
import pandas as pd

sales = pd.DataFrame({
"region": ["east", "east", "west", None], "product": ["A", "A", "B", "A"],
"amount": [10.0, 30.0, 0.0, 5.0], "order_id": [1, 2, 3, 4],
})
summary = (
sales.groupby(["region", "product"], as_index=False, dropna=False, observed=True)
.agg(revenue=("amount", "sum"), orders=("order_id", "nunique"))
)

totals = sales.groupby("region", dropna=False, observed=True)["amount"].transform("sum")
sales["region_share"] = sales["amount"].div(totals.where(totals.ne(0)))

使用具名聚合(Named Aggregation)时,需同时指定源列和输出列名。通常情况下,内置的分组操作比自定义 Python 回调更清晰,性能也更好。

关键参数决策

  • dropna:默认 True 会丢弃分组键为缺失值的行。如果“缺失”本身代表一个有意义的组,需显式设为 False
  • observed:影响分类变量(Categorical)分组时,未出现的类别是否显示。若需保证跨版本输出形状一致,建议显式设置。
  • sort:若分组顺序无关紧要,设 sort=False 可避免不必要的排序开销。
  • as_index:设为 False 可将分组键保留为普通列,通常能简化后续的数据处理流程。

MultiIndex 输出

多键分组常产生 MultiIndex。如果层级结构对后续筛选有用,就保留它;否则,使用 as_index=Falsereset_index() 将其展平为普通表格。

apply 的使用边界

仅当算法逻辑确实基于组结构,且无法通过聚合、转换、筛选、窗口函数或连接(Join)表达时,才使用 GroupBy.apply。 注意:不要在函数内部修改组对象,并务必显式测试索引行为,因为 apply 的索引处理往往不如其他方法直观。

把分组总量对应回原行

这里 summary 有三行:east/A 的收入为 40、不同订单数为 2;west/B 为 0 和 1;地区缺失的 A 组为 5 和 1。transform("sum") 把组总量广播回原行,得到 [40, 40, 0, 5],并保留原始行索引。占比为 [0.25, 0.75, NaN, 1.0],总量为零的组没有可定义的占比。

分组 API 中,size 统计行数,count 统计所选列的非缺失值数,nunique 默认统计不同的非缺失值数,三者回答的问题不同。分组求和会跳过缺失值,全缺失组可能得到零;若应保留未知,用 sum(min_count=1)filter(lambda g: len(g) >= 2) 会保留 east 的两条原始行,而不是生成汇总行。

参考

探索关联打开关联网络