前言
“split-apply-combine”(拆分-应用-合并)很好地描述了分组运算的整个过程。
分组运算的第一个阶段,pandas对象(无论是Series、DataFrame还是其他的)中的数据会根据所提供的一个或多个键被拆分(split)为多组。
拆分操作是在对象的特定轴上执行的。例如,DataFrame可以在其行(axis=0)或列(axis=1)上进行分组。
然后,将一个函数应用(apply)到各个分组并产生一个新值。
最后,所有这些函数的执行结果会被合并(combine)到最终的结果对象中。结果对象的形式一般取决于数据上所执行的操作。
下图,大致说明了一个简单的分组聚合过程:
分组键
分组键可以有多种形式,且类型不必相同:
- 列表或数组,其长度与待分组的轴一样。
- 表示DataFrame某个列名的值。
- 字典或Series,给出待分组轴上的值与分组名之间的对应关系。
- 函数,用于处理轴索引中的各个标签。
注意:后三种都只是快捷方式而已,其最终目的仍然是产生一组用于拆分对象的值。
先了解一下表格型数据集(以DataFrame的形式):
In [1]: import numpy as np
In [2]: import pandas as pd
In [3]: from pandas import Series,DataFrame
In [4]: df=DataFrame({'key1':['a','a','b','b','a'],
'key2':['one','two','one','two','one'],
'data1':np.random.randn(5),
'data2':np.random.randn(5)})
In [5]: df
Out[5]:
key1 key2 data1 data2
0 a one -0.549915 -1.567342
1 a two -0.037543 -0.834576
2 b one -1.267072 1.628881
3 b two 0.976757 -1.549664
4 a one 2.423714 1.791845
假设想要按key1进行分组,并计算data1列的平均值。实现方式:访问data1,并根据key1调用groupby:
In [6]: grouped=df['data1'].groupby(df['key1'])
In [7]: grouped
Out[7]: <pandas.core.groupby.generic.SeriesGroupBy object at 0x119840240>
变量grouped是一个GroupBy对象。它实际上还没有进行任何计算,只是含有一些有关分组键df[‘key1’]的中间数据而已。换句话说,该对象已经有了接下来对各组执行运算所需的一切信息。例如,可以调用GroupBy的mean方法来计算分组平均值:
In [8]: grouped.mean()
Out[8]:
key1
a 0.612085
b -0.145158
Name: data1, dtype: float64
四种分组键使用方法,具体如下:
一次传入多个数组
In [9]: means=df['data1'].groupby([df['key1'],df['key2']]).mean()
In [10]: means
Out[10]:
key1 key2
a one 0.936899
two -0.037543
b one -1.267072
two 0.976757
Name: data1, dtype: float64
通过两个键对数据进行了分组,得到的Series具有一个层次化索引(由唯一的键对组成):
In [11]: means.unstack()
Out[11]:
key2 one two
key1
a 0.936899 -0.037543
b -1.267072 0.976757
分组键可以是任何长度适当的数组
In [12]: states=np.array(['Ohio','California','California','Ohio','Ohio'])
In [13]: years=np.array([2005,2005,2006,2005,2006])
In [14]: df['data1'].groupby([states,years]).mean()
Out[14]:
California 2005 -0.037543
2006 -1.267072
Ohio 2005 0.213421
2006 2.423714
Name: data1, dtype: float64
将列名(可以是字符串、数字或其他python对象)用作分组键
In [15]: df.groupby('key1').mean()
Out[15]:
data1 data2
key1
a 0.612085 -0.203358
b -0.145158 0.039609
在执行df.groupby('key1').mean()时,结果中没有key2列。这是因为df[‘key2’]不是数值数据(俗称“麻烦列”),所以被从结果中排除了。默认情况下,所有数据列都会被整合,虽然有时会被过滤为一个子集。
In [16]: df.groupby(['key1','key2']).mean()
Out[16]:
data1 data2
key1 key2
a one 0.936899 0.112251
two -0.037543 -0.834576
b one -1.267072 1.628881
two 0.976757 -1.549664
GroupBy的size方法
返回一个含有分组大小的Series:
In [17]: df.groupby(['key1','key2']).size()
Out[17]:
key1 key2
a one 2
two 1
b one 1
two 1
dtype: int64