面向列的聚合方法
当内置方法无法满足聚合要求时,这时可以自定义一个函数,将它传入给agg()方法(pandas 0.20版本后,aggregate与agg方法用法一样)实现对Series或DataFrame对象进行聚合运算。
agg()方法的语法格式如下:
agg(func,axis = 0,* args,** kwargs )
上述方法中部分参数表示的含义如下:
(1) func:表示用于汇总数据的函数,可以为单个函数或函数列表。
(2) axis:表示函数作用于轴的方向,0或index表示将函数应用到每一列; 1或columns表示将函数应用到每一行,该参数的默认值为0。
需要注意的是,通过agg()方法进行聚合时,func参数既可以接收Pandas中的内置方法,也可以接收自定义的函数,同时,这些方法与函数可以作用于每一列,也可以将多个函数或方法作用于同一列,还可以将不同函数或方法作用于不同的列,下面来进行详细地讲解。
1. 对每一列数据应用同一个函数
使用agg()方法的最简单的方式,就是给该方法的func参数传入一个函数,这个函数既可以是内置的,也可以自定义的。
假设现在有一个6行7列的表格,从左边数表格的前6列都是数值类型,而第7列的数据类型为字符串类型,如图1所示。
a | b | c | d | e | f | key | |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 | 5 | a |
1 | 6 | 7 | 8 | 9 | 10 | 11 | a |
2 | 12 | 13 | 14 | 15 | 16 | 17 | a |
3 | 18 | 19 | 20 | 21 | 22 | 23 | b |
4 | 24 | 25 | 26 | 27 | 28 | 29 | b |
5 | 30 | 31 | 32 | 33 | 34 | 35 | b |
图1 表格示例
按图1中的key一列进行分组,将上述表格拆分为a、b两组,并且分别计算两个分组中每列数据的和,将得到的结果整合到一起。
首先,创建一个与图1结构相同的DataFrame对象,示例代码如下。
In [15]: from pandas import DataFrame, Series
import numpy as np
data_frame = DataFrame(np.arange(36).reshape((6, 6)),columns=list('abcdef'))
data_frame['key'] = Series(list('aaabbb'), name='key')
data_frame
Out[15]:
a b c d e f key
0 0 1 2 3 4 5 a
1 6 7 8 9 10 11 a
2 12 13 14 15 16 17 a
3 18 19 20 21 22 23 b
4 24 25 26 27 28 29 b
5 30 31 32 33 34 35 b
然后,将data_frame对象以“key”列为分组键进行分组,凡是该列中数据为“a”的划分为一组,数据为“b”的划分成另外一组,两个分组的结构如图2所示。
图2 a组和b组的数据
接下来,通过代码来实现上述分组的过程,并且通过字典的形式分别打印出每个分组的具体内容,示例代码如下。
In [16]: # 按key列进行分组
data_group = data_frame.groupby('key')
# 输出a组数据信息
dict([x for x in data_group])['a']
Out[16]:
a b c d e f key
0 0 1 2 3 4 5 a
1 6 7 8 9 10 11 a
2 12 13 14 15 16 17 a
In [17]: # 输出b组数据信息
dict([x for x in data_group])['b']
Out[17]:
a b c d e f key
3 18 19 20 21 22 23 b
4 24 25 26 27 28 29 b
5 30 31 32 33 34 35 b
上述示例中,首先调用groupby()方法,按key一列的数据将data_frame对象进行分组,共分为a、b两组,然后使用列表推导式遍历分组对象data_group,得到的是每个分组的列表,之后将装有分组的列表强转为字典,其中字典中的键为a和b,字典的值为分组的具体内容。
通过“字典[组名]”的形式,先查看了a组的数据,再查看了b组的数据。
接下来,便可以对每个分组的数据进行聚合运算。例如,调用agg()方法时传入内置的求和方法sum(),示例代码如下。
In [18]: # 求每个分组的和
data_group.agg(sum)
Out[18]:
a b c d e f
key
a 18 21 24 27 30 33
b 72 75 78 81 84 87
当然,在使用agg()方法进行聚合时也可以传入自定义的函数。例如,定义一个range_data_group()函数,用来计算每个分组数据的极差值(极差值=最大值–最小值),函数的定义具体如下。
In [19]: def range_data_group(arr):
return arr.max()-arr.min()
接下来,将上述自定义函数作为参数传入到agg()方法中,让每个分组的数据都执行上述函数求极差值,具体代码如下。
In [20]: data_group.agg(range_data_group) # 使用自定义函数聚合分组数据
Out[20]:
a b c d e f
key
a 12 12 12 12 12 12
b 12 12 12 12 12 12
2. 对某列数据应用不同的函数
假设现在产生另外一个需求,不仅需要求出每组数据的极差,还需要计算出每组数据的和,即对一列数据使用两种不同的函数。这时,可以将两个函数的名称放在列表中,之后在调用agg()方法聚合时作为参数传入即可,具体示例代码如下。
In [21]: # 对一列数据用两种函数聚合
data_group.agg([range_data_group, sum])
Out[21]:
a b ... e f
range_data_group sum range_data_group ... sum range_data_group sum
key ...
a 12 18 12 ... 30 12 33
b 12 72 12 ... 84 12 87
[2 rows x 12 columns]
从输出的结果可以看出,生成的DataFrame对象具有两层列索引,每个外层列索引包含两个内层列索引,分别以函数的名称range_data_group和sum命名。
虽然每一列可以应用不同的函数,但是结果并不能很直观地辨别出每个函数代表的含义。Pandas的设计者已经考虑到这一点,为了能更好地反映出每列对应的数据的信息,可以使用“(name,function)”元组将function(函数名)替换为name(自定义名称)。下面,在上述示例中进一步优化内层索引的名称,具体代码如下。
In [22]: data_group.agg([("极差", range_data_group), ("和", sum)])
Out[22]:
a b c d e f
极差 和 极差 和 极差 和 极差 和 极差 和 极差 和
key
a 12 18 12 21 12 24 12 27 12 30 12 33
b 12 72 12 75 12 78 12 81 12 84 12 87
从输出的结果可以看出,函数名经过重命名以后,可以很清晰直观地找到每组数据的极差值以及总和。
3. 对不同列数据应用不同函数
如果希望对不同的列使用不同的函数,则可以在agg()方法中传入一个{"列名":"函数名"}格式的字典。接下来,在上述示例的基础上,使用字典来聚合data_group对象,具体代码如下。
In [23]: # 每列使用不同的函数聚合分组数据
data_group.agg({'a': 'sum', 'b': 'mean', 'c': range_data_group})
Out[23]:
a b c
key
a 18 7 12
b 72 25 12
上述示例中,使用不同的函数对每个分组执行聚合运算,其中a列数据执行求和运算,b列数据执行平均值计算,c列数据执行求极差计算。需要注意的是,自定义函数不需要加引号。
注意:
agg()方法执行聚合操作时,会将一组标量值参与某些运算后转换为一个标量值。