groupby().apply() 慢的根本原因是它在 Python 层逐组调用函数,绕过 pandas 底层 C/Fortran 向量化引擎,导致拷贝子对象并承受解释器开销,性能比 agg 低 5–20 倍。
groupby().apply() 慢得离谱?根本原因就一个:它在 Python 层面逐组调用函数,完全绕过了 pandas 底层的 C/Fortran 向量化引擎。哪怕你只写 lambda x: x.mean(),apply 也会把每个子 Series 或 DataFrame 拷贝出来、交由 Python 解释器执行——这和直接用 .agg('mean') 调用底层优化过的 C 函数,性能差 5–20 倍很常见。
apply 本质是“封装了 for 循环”的接口,不管函数多简单,都触发解释器开销agg 和 transform 优先走内置路径(如 'sum'、'first'),能直接映射到底层向量化实现agg 或 transform 时也会变慢,但比 apply 好——因为至少避免了额外的子对象构造和索引重建apply vs agg vs transform:该选谁?看你要的是“聚合结果”还是“扩展结果”,以及函数是否可向量化:
agg,字符串名('mean')比函数对象快得多transform,但别传复杂 lambda;transform('zscore') 可以,transform(lambda x: (x - x.mean()) / x.std()) 就不行apply,且务必加 result_type='expand' 或提前预设返回结构,避免 pandas 自动推断耗时agg,其实掉进了 apply 的坑这种写法:df.groupby('key').agg({'col': lambda x: x.max() - x.min()}),看着像 agg,实则等价于 apply——因为用了 lambda,pandas 无法识别为内置函数,只能退化为 Python 循环。
df.groupby('key')['col'].agg(['min', 'max']).apply(lambda row: row['max'] - row['min'], axis=1)(先批量算,再轻量计算)df.groupby('key')['col'].agg(lambda x: x.max() - x.min()) —— 注意这里是 SeriesGroupBy.agg,不是 DataFrameGroupBy.agg,路径更短,开销略小agg 字典里混用字符串和函数,会强制统一走慢路径pandas 的 groupby 是惰性求值的,但 apply 会立刻触发分组切片和对象构造,而 agg 在多数内置场景下可延迟到最终计算才真正分组。
df.groupby(...).apply(...).sort_values(...) → 每次都重算分组g = df.groupby(['a', 'b']),再分别调 g.agg(...)、g.transform(...) —— 分组只做一次,后续复用apply,加 engine='numba'(仅限数值列+简单函数)或改用 swifter 包自动 fallback,但别指望翻倍提升真正卡住你的,往往不是“会不会写”,而是没意识到 apply 这个名字背后藏着一层 Python 循环胶水——它