1. 内置聚合函数
在介绍agg之前,首先要了解一些直接定义在groupby对象的聚合函数,因为它的速度基本都会经过内部的优化,使用功能时应当优先考虑。根据返回标量值的原则,包括如下函数: max/min/mean/median/count/all/any/idxmax/idxmin/mad/nunique/skew/quantile/sum/std/var/sem/size/prod
。
In [20]: gb = df.groupby('Gender')['Height']
In [21]: gb.idxmin()
Out[21]:
Gender
Female 143
Male 199
Name: Height, dtype: int64
In [22]: gb.quantile(0.95)
Out[22]:
Gender
Female 166.8
Male 185.9
Name: Height, dtype: float64
练一练
请查阅文档,明确
all/any/mad/skew/sem/prod
函数的含义。
这些聚合函数当传入的数据来源包含多个列时,将按照列进行迭代计算:
In [23]: gb = df.groupby('Gender')[['Height', 'Weight']]
In [24]: gb.max()
Out[24]:
Height Weight
Gender
Female 170.2 63.0
Male 193.9 89.0
2. agg方法
虽然在 groupby
对象上定义了许多方便的函数,但仍然有以下不便之处:
- 无法同时使用多个函数
- 无法对特定的列使用特定的聚合函数
- 无法使用自定义的聚合函数
- 无法直接对结果的列名在聚合前进行自定义命名
下面说明如何通过 agg
函数解决这四类问题:
【a】使用多个函数
当使用多个聚合函数时,需要用列表的形式把内置聚合函数对应的字符串传入,先前提到的所有字符串都是合法的。
In [25]: gb.agg(['sum', 'idxmax', 'skew'])
Out[25]:
Height Weight
sum idxmax skew sum idxmax skew
Gender
Female 21014.0 28 -0.219253 6469.0 28 -0.268482
Male 8854.9 193 0.437535 3929.0 2 -0.332393
从结果看,此时的列索引为多级索引,第一层为数据源,第二层为使用的聚合方法,分别逐一对列使用聚合,因此结果为6列。
对于方法和列的特殊对应,可以通过构造字典传入 agg
中实现,其中字典以列名为键,以聚合字符串或字符串列表为值。
In [26]: gb.agg({'Height':['mean','max'], 'Weight':'count'})
Out[26]:
Height Weight
mean max count
Gender
Female 159.19697 170.2 135
Male 173.62549 193.9 54
练一练
请使用【b】中的传入字典的方法完成【a】中等价的聚合任务。
【c】使用自定义函数
在 agg
中可以使用具体的自定义函数, 需要注意传入函数的参数是之前数据源中的列,逐列进行计算 。下面分组计算身高和体重的极差:
In [27]: gb.agg(lambda x: x.mean()-x.min())
Out[27]:
Height Weight
Gender
Female 13.79697 13.918519
Male 17.92549 21.759259
练一练
在
groupby
对象中可以使用describe
方法进行统计信息汇总,请同时使用多个聚合函数,完成与该方法相同的功能。
由于传入的是序列,因此序列上的方法和属性都是可以在函数中使用的,只需保证返回值是标量即可。下面的例子是指,如果组的指标均值,超过该指标的总体均值,返回High,否则返回Low。
In [28]: def my_func(s):
....: res = 'High'
....: if s.mean() <= df[s.name].mean():
....: res = 'Low'
....: return res
....:
In [29]: gb.agg(my_func)
Out[29]:
Height Weight
Gender
Female Low Low
Male High High
【d】聚合结果重命名
如果想要对聚合结果的列名进行重命名,只需要将上述函数的位置改写成元组,元组的第一个元素为新的名字,第二个位置为原来的函数,包括聚合字符串和自定义函数,现举若干例子说明:
In [30]: gb.agg([('range', lambda x: x.max()-x.min()), ('my_sum', 'sum')])
Out[30]:
Height Weight
range my_sum range my_sum
Gender
Female 24.8 21014.0 29.0 6469.0
Male 38.2 8854.9 38.0 3929.0
In [31]: gb.agg({'Height': [('my_func', my_func), 'sum'],
....: 'Weight': lambda x:x.max()})
....:
Out[31]:
Height Weight
my_func sum <lambda>
Gender
Female Low 21014.0 63.0
Male High 8854.9 89.0
另外需要注意,使用对一个或者多个列使用单个聚合的时候,重命名需要加方括号,否则就不知道是新的名字还是手误输错的内置函数字符串:
In [32]: gb.agg([('my_sum', 'sum')])
Out[32]:
Height Weight
my_sum my_sum
Gender
Female 21014.0 6469.0
Male 8854.9 3929.0
In [33]: gb.agg({'Height': [('my_func', my_func), 'sum'],
....: 'Weight': [('range', lambda x:x.max())]})
....:
Out[33]:
Height Weight
my_func sum range
Gender
Female Low 21014.0 63.0
Male High 8854.9 89.0