学科分类
目录
数据分析

面向列的聚合方法

当内置方法无法满足聚合要求时,这时可以自定义一个函数,将它传入给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所示。

image-20200618140906044

图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()方法执行聚合操作时,会将一组标量值参与某些运算后转换为一个标量值。

点击此处
隐藏目录