分组键可以有很多形式,且类型不必相同:
1、列表或数组,其长度与待分组的轴一样
2、表示DataFrame某个列名的值
3、字典或Series,给出待分组轴上的值与分组名之间的对应关系
4、函数,用于处理轴索引或索引中的各个标签
1、分组键为Series
1 df=DataFrame({ 'key1':['a','a','b','b','a'], 2 'key2':['one','two','one','two','one'], 3 'data1':np.random.randn(5), 4 'data2':np.random.randn(5)}) 5 6 df 7 Out[6]: 8 data1 data2 key1 key2 9 0 -0.814074 1.244593 a one10 1 -1.203203 -0.199076 a two11 2 0.846649 1.136826 b one12 3 -1.700835 1.822935 b two13 4 1.190682 -2.001369 a one
按照key1进行分组,并计算data1列的平均值,这里使用:访问data1,并根据key1调用groupby:
1 grouped=df['data1'].groupby(df['key1'])2 grouped3 Out[6]:
变量grouped是一个GroupBy对象。实际上还没有进行任何计算,只是含有一些有关分组键df['key1']的中间数据。换句话说,该对象已经有了接下来对个分组执行运算所需的一切信息。
1 #调用GroupBy的mean方法计算分组平均值2 grouped.mean()3 Out[8]: 4 key15 a -0.2755326 b -0.4270937 Name: data1, dtype: float64
可以看出,数据(Series)根据分组键进行了聚合,产生了一个新的Series,其索引为key1列中的唯一值。之所以结果中索引的名称为key1,是因为原始DataFrame的列df['key1']就叫这个名字。
一次传入多个数组:
1 #一次传入多个数组,使用列表方式[] 2 means=df['data1'].groupby([df['key1'],df['key2']]).mean() 3 4 means 5 Out[11]: 6 key1 key2 7 a one 0.188304 8 two -1.203203 9 b one 0.84664910 two -1.70083511 Name: data1, dtype: float6412 13 #分组后得到的Series具有一个层次化索引14 means.unstack()15 Out[12]: 16 key2 one two17 key1 18 a 0.188304 -1.20320319 b 0.846649 -1.700835
2、分组键是数组
上面的示例中,分组键均为Series,实际上, 分组键可以是任何长度适当的数组:
1 states=np.array(['Ohio','California','California','Ohio','Ohio']) 2 3 years=np.array([2005,2005,2006,2005,2006]) 4 5 df['data1'].groupby([states,years]).mean() 6 Out[15]: 7 California 2005 -1.203203 8 2006 0.846649 9 Ohio 2005 -1.25745410 2006 1.19068211 Name: data1, dtype: float64
3、列名做分组键
此外还可以将列名(可以是字符串、数字或其他Python对象)作为分组键:
1 df.groupby('key1').mean() 2 Out[16]: 3 data1 data2 4 key1 5 a -0.275532 -0.318617 6 b -0.427093 1.479880 7 8 df.groupby(['key1','key2']).mean() 9 Out[17]: 10 data1 data211 key1 key2 12 a one 0.188304 -0.37838813 two -1.203203 -0.19907614 b one 0.846649 1.13682615 two -1.700835 1.822935
可以注意到,在执行df.groupby('key1').mean()时,结果中没有key2列。这是因为df['key2']不是数值数据(俗称“麻烦列”),所以从结果中排除了。 默认情况下,所有数值列都会被聚合。
GroupBy的size方法,它可以返回一个含有分组大小的Series:
1 df.groupby(['key1','key2']).size()2 Out[18]: 3 key1 key24 a one 25 two 16 b one 17 two 18 dtype: int64
对分组进行迭代
GroupBy对象支持迭代,可以产生一组二元元组(由分组名和数据块组成)。
1 for name,group in df.groupby('key1'): 2 print(name) 3 print(group) 4 5 a 6 data1 data2 key1 key2 7 0 -0.814074 1.244593 a one 8 1 -1.203203 -0.199076 a two 9 4 1.190682 -2.001369 a one10 b11 data1 data2 key1 key212 2 0.846649 1.136826 b one13 3 -1.700835 1.822935 b two
多重键,元组的第一个元素将会是由键值组成的元组:
1 for (k1,k2),group in df.groupby(['key1','key2']): 2 print(k1,k2) 3 print(group) 4 5 a one 6 data1 data2 key1 key2 7 0 -0.814074 1.244593 a one 8 4 1.190682 -2.001369 a one 9 a two10 data1 data2 key1 key211 1 -1.203203 -0.199076 a two12 b one13 data1 data2 key1 key214 2 0.846649 1.136826 b one15 b two16 data1 data2 key1 key217 3 -1.700835 1.822935 b two
可以对这些数据片段做任何操作,例如:将这些数据片段做成一个字典。
1 pieces=dict(list(df.groupby('key1'))) 2 3 pieces 4 Out[24]: 5 { 'a': data1 data2 key1 key2 6 0 -0.814074 1.244593 a one 7 1 -1.203203 -0.199076 a two 8 4 1.190682 -2.001369 a one, 'b': data1 data2 key1 key2 9 2 0.846649 1.136826 b one10 3 -1.700835 1.822935 b two}11 12 pieces['b']13 Out[25]: 14 data1 data2 key1 key215 2 0.846649 1.136826 b one16 3 -1.700835 1.822935 b two
groupby默认是在axis=0上进行分组的,通过设置也可以在其他任何轴上进行分组。
1 df.dtypes 2 Out[26]: 3 data1 float64 4 data2 float64 5 key1 object 6 key2 object 7 dtype: object 8 9 #在axis=1分组10 grouped=df.groupby(df.dtypes,axis=1)11 dict(list(grouped))12 Out[29]: 13 {dtype('float64'): data1 data214 0 -0.814074 1.24459315 1 -1.203203 -0.19907616 2 0.846649 1.13682617 3 -1.700835 1.82293518 4 1.190682 -2.001369, dtype('O'): key1 key219 0 a one20 1 a two21 2 b one22 3 b two23 4 a one}
选取一个或一组列
对于由DataFrame产生的GroupBy对象,如果用一个(单个字符串)或一组(字符串数组)列名对其进行索引,就能实现选取部分列进行聚合的目的。
1 df.groupby('key1')['data1']2 df.groupby('key1')[[data2']]3 #上面的代码是下面代码的语法糖4 df['data1'].groupby(df['key1'])5 df[['data2']].groupby(df['key1'])
1 #对部分列进行聚合2 df.groupby(['key1','key2'])[['data2']].mean()3 Out[32]: 4 data25 key1 key2 6 a one -0.3783887 two -0.1990768 b one 1.1368269 two 1.822935
这样操作返回的对象是一个已分组的DataFrame(传入的是列表或数组)或已分组的Series(传入的是标量形式的单个列名):
1 s_grouped=df.groupby(['key1','key2'])['data2']2 s_grouped.mean()3 Out[36]: 4 key1 key25 a one -0.3783886 two -0.1990767 b one 1.1368268 two 1.8229359 Name: data2, dtype: float64
4、通过字典或Series进行分组
1 people=DataFrame(np.random.randn(5,5), 2 columns=['a','b','c','d','e'], 3 index=['Joe','Steve','Wes','Jim','Travis']) 4 5 #将行索引为2,列索引名为'b','c'的数据赋值为NaN 6 people.ix[2:3,['b','c']]=np.nan 7 __main__:1: DeprecationWarning: 8 .ix is deprecated. Please use 9 .loc for label based indexing or10 .iloc for positional indexing11 12 See the documentation here:13 http://pandas.pydata.org/pandas-docs/stable/indexing.html#ix-indexer-is-deprecated14 15 people16 Out[42]: 17 a b c d e18 Joe 0.125621 -0.059778 0.437543 -1.583435 0.47284919 Steve 0.855371 0.461129 -0.126290 0.146014 0.37391320 Wes -2.106125 NaN NaN 0.895130 -1.54735821 Jim 0.155206 0.202384 0.932044 -1.171872 -1.03531322 Travis 0.875559 -0.161025 0.482190 1.593750 0.637874
假设已知列的分组关系,并希望根据分组计算列的总计:
1 mapping={ 'a':'red','b':'red','c':'blue', 2 'd':'blue','e':'red','f':'orange'} 3 4 #将mapping这个字典传给groupby 5 by_column=people.groupby(mapping,axis=1) 6 7 by_column.sum() 8 Out[45]: 9 blue red10 Joe -1.145892 0.53869211 Steve 0.019724 1.69041312 Wes 0.895130 -3.65348313 Jim -0.239828 -0.67772214 Travis 2.075939 1.352408
5、用Series做分组键
Series也有同样的功能,被看做一个固定大小的映射。用Series做分组键,pandas会检查Series以确保其索引跟分组轴是对齐的:
1 map_series=Series(mapping) 2 3 map_series 4 Out[48]: 5 a red 6 b red 7 c blue 8 d blue 9 e red10 f orange11 dtype: object12 13 people.groupby(map_series,axis=1).count()14 Out[49]: 15 blue red16 Joe 2 317 Steve 2 318 Wes 1 219 Jim 2 320 Travis 2 3
6、通过函数进行分组
任何被当做分组键的函数都会在各个索引值上被调用一次,其返回值就会被用作分组名称。
1 people.groupby(len).sum()2 Out[50]: 3 a b c d e4 3 -1.825298 0.142606 1.369587 -1.860177 -2.1098225 5 0.855371 0.461129 -0.126290 0.146014 0.3739136 6 0.875559 -0.161025 0.482190 1.593750 0.637874
将函数和数组、列表、字典、Series混合使用也必是问题,因为任何东西最终都会被转换为数组:
1 key_list=['one','one','one','two','two']2 people.groupby([len,key_list]).min()3 Out[53]: 4 a b c d e5 3 one -2.106125 -0.059778 0.437543 -1.583435 -1.5473586 two 0.155206 0.202384 0.932044 -1.171872 -1.0353137 5 one 0.855371 0.461129 -0.126290 0.146014 0.3739138 6 two 0.875559 -0.161025 0.482190 1.593750 0.637874
7、根据索引级别分组
层次化索引数据集最方便的地方在于能够根据索引级别进行聚合。
1 columns=pd.MultiIndex.from_arrays([['US','US','US','JP','JP'], 2 [1,3,5,1,3]],names=['cty','tenor']) 3 4 hier_df=DataFrame(np.random.randn(4,5),columns=columns) 5 6 hier_df 7 Out[58]: 8 cty US JP 9 tenor 1 3 5 1 310 0 1.641749 2.434674 -0.546666 0.797418 0.53001911 1 0.084086 0.309776 -0.322581 1.996448 -0.09379112 2 1.387329 -0.200419 -0.182946 -0.811081 1.08150113 3 -0.237261 0.288679 -0.057882 0.267184 0.90747814 15 16 #通过level关键字传入级别编号或名称17 hier_df.groupby(level='cty',axis=1).count()18 Out[59]: 19 cty JP US20 0 2 321 1 2 322 2 2 323 3 2 3