Pandas groupby中agg、apply与transform的区别详解

阿橙
阿橙
发布时间:2026-10-14 | 6人浏览过
原创

本文详细解析Pandas中groupby后的agg、apply和transform三个方法的核心区别。agg针对单列返回标量,apply接收整个DataFrame并支持复杂逻辑,transform则保持原索引进行广播。通过具体代码实例说明如何在不同场景下选择合适的方法,并解决groupby索引冗余等常见问题。

agg方法主要作用于单列数据,接收一个Series作为输入,执行聚合操作后返回一个标量值。这意味着每次调用时,它处理的是分组后的某一列数据,最终输出该列的聚合结果。

示例展示了如何对单一列应用多个不同的聚合函数。

当需要对不同列应用不同的聚合逻辑时,agg可以通过字典形式指定每列对应的函数,实现灵活的多列处理。

apply是一个更为通用的方法,遵循“拆分-应用-合并”的模式。与agg不同,apply将当前分组后的整个DataFrame作为参数传入函数,因此它可以处理多列数据,并返回多维结果(如Series或DataFrame),而不仅仅是标量。

具体应用场景如下:

1、基础数据示例:


lawsuit2[['EID','LAWAMOUNT','LAWDATE']]

2、在groupby后应用apply,传入的函数接收的是整个分组后的DataFrame对象:


lawsuit2[['EID','LAWAMOUNT','LAWDATE']].groupby(['EID']).apply(lambda df:print(df))

3、若使用agg处理多列,虽然可以处理两列,但若尝试在lambda中直接访问其他列(如通过df['其他列']),可能会因为传入的是单列Series而引发KeyError,除非显式处理列索引:


lawsuit2[['EID','LAWAMOUNT','LAWDATE']].groupby(['EID']).agg(lambda df:print(df))

从上述输出可见,agg传入函数的仅是单列数据。虽然可以通过df.iloc或特定方式强行获取其他列信息,但这容易引发KeyError等错误,且代码可读性较差。

4、完整实现代码:

目标:判断每个分组中最近一次日期的花费,是否为该组所有花费中的最大值。


def handle(df):
#   print(df)
# 找最大日期
  maxdate = df['LAWDATE'].max()
# 找最大费用
  left = df[ df['LAWDATE']==maxdate ]['LAWAMOUNT'].max()
# 取ID
  EID = df['EID'].values[0]
#   print(EID)
# 从已存在的表中根据EID找到最大费用
  right = LAW_AMOUNT_MAX.loc[EID,'LAW_AMOUNT_MAX']
# 判断费用是否相等
  if left==right:
    return 1
  else:
    return 0
    
LAW_AMOUNT_MAX_IS_LAST = lawsuit2[['EID','LAWAMOUNT','LAWDATE']].groupby(['EID']).apply(handle)

其他注意事项:

在groupby后使用apply时,如果直接返回结果,可能会产生多余的层级索引(MultiIndex)。可以通过设置group_keys=False参数来避免这一问题:


orgin = reviews_df.sort_values(["reviewerID","unixReviewTime"]).groupby("reviewerID",group_keys=False)
train = orgin.apply(lambda df: df[:-2])
train.head()

补充:Pandas分组聚合运算中groupby、agg、apply和transform的综合对比。

groupby函数用于根据指定列对数据进行分组,返回GroupBy对象。虽然Pandas提供了sum、mean等优化过的聚合函数,但在需要自定义复杂逻辑时,需借助agg、apply或transform。

三者的核心区别在于:1. agg与transform的区别:agg聚合后仅返回该组单列的一个标量值;transform则将这个标量值广播回原DataFrame的索引位置,保持索引结构不变。2. 参数对象不同:agg和transform接收的是分组后的单列(Series),而apply接收的是分组后的整个DataFrame。

一、agg与transform对比

如代码所示,构造DataFrame后,agg和transform中的lambda函数输入均为单列Series。但agg返回的索引是分组键的唯一值,而transform返回的索引与原DataFrame一致。观察发现,transform实际上是将聚合结果(如形状)广播到原数据的每一行,从而维持原索引结构,且参与分组的列会被剔除。


df
Out[1]:
 index a b c
0   d 0 1 2
1   d 3 4 5
2   e 6 7 8
 
df.groupby(by='index').agg(lambda x:x.shape)
Out[2]: 
     a   b   c
index         
d   (2,) (2,) (2,)
e   (1,) (1,) (1,)
 
df.groupby(by='index').transform(lambda x:x.shape)
Out[3]: 
   a   b   c
0 (2,) (2,) (2,)
1 (2,) (2,) (2,)
2 (1,) (1,) (1,) 

二、agg与apply对比

apply的结果显示,其lambda函数的输入不再是单列Series,而是分组后的完整DataFrame对象,这使得处理多列交互成为可能。


dd.groupby(by='index').apply(lambda x:x.shape)
Out[4]: 
index
d  (2, 4)
e  (1, 4)

三、其他关键注意点

agg不仅支持对每列执行相同操作,还支持传入字典{'列名': 函数}以对不同列执行不同操作,或传入函数列表对同一列执行多个操作,这是agg最灵活的特性。

这三个函数的参数形式均为(func, *args, **kwargs),因此可以通过位置参数或关键字参数向自定义函数传递额外参数。

以上内容为个人经验总结,旨在提供清晰参考。如有疏漏或错误,欢迎指正。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表