分組鍵可以有很多形式,且類型不必相同:
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 one 10 1 -1.203203 -0.199076 a two 11 2 0.846649 1.136826 b one 12 3 -1.700835 1.822935 b two 13 4 1.190682 -2.001369 a one
按照key1進行分組,並計算data1列的平均值,這里使用:訪問data1,並根據key1調用groupby:
1 grouped=df['data1'].groupby(df['key1']) 2 grouped 3 Out[6]: <pandas.core.groupby.SeriesGroupBy object at 0x000000000ADEEC18>
變量grouped是一個GroupBy對象。實際上還沒有進行任何計算,只是含有一些有關分組鍵df['key1']的中間數據。換句話說,該對象已經有了接下來對個分組執行運算所需的一切信息。
1 #調用GroupBy的mean方法計算分組平均值 2 grouped.mean() 3 Out[8]: 4 key1 5 a -0.275532 6 b -0.427093 7 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.846649 10 two -1.700835 11 Name: data1, dtype: float64 12 13 #分組后得到的Series具有一個層次化索引 14 means.unstack() 15 Out[12]: 16 key2 one two 17 key1 18 a 0.188304 -1.203203 19 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.257454 10 2006 1.190682 11 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 data2 11 key1 key2 12 a one 0.188304 -0.378388 13 two -1.203203 -0.199076 14 b one 0.846649 1.136826 15 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 key2 4 a one 2 5 two 1 6 b one 1 7 two 1 8 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 one 10 b 11 data1 data2 key1 key2 12 2 0.846649 1.136826 b one 13 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 two 10 data1 data2 key1 key2 11 1 -1.203203 -0.199076 a two 12 b one 13 data1 data2 key1 key2 14 2 0.846649 1.136826 b one 15 b two 16 data1 data2 key1 key2 17 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 one 10 3 -1.700835 1.822935 b two} 11 12 pieces['b'] 13 Out[25]: 14 data1 data2 key1 key2 15 2 0.846649 1.136826 b one 16 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 data2 14 0 -0.814074 1.244593 15 1 -1.203203 -0.199076 16 2 0.846649 1.136826 17 3 -1.700835 1.822935 18 4 1.190682 -2.001369, dtype('O'): key1 key2 19 0 a one 20 1 a two 21 2 b one 22 3 b two 23 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 data2 5 key1 key2 6 a one -0.378388 7 two -0.199076 8 b one 1.136826 9 two 1.822935
這樣操作返回的對象是一個已分組的DataFrame(傳入的是列表或數組)或已分組的Series(傳入的是標量形式的單個列名):
1 s_grouped=df.groupby(['key1','key2'])['data2'] 2 s_grouped.mean() 3 Out[36]: 4 key1 key2 5 a one -0.378388 6 two -0.199076 7 b one 1.136826 8 two 1.822935 9 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 or 10 .iloc for positional indexing 11 12 See the documentation here: 13 http://pandas.pydata.org/pandas-docs/stable/indexing.html#ix-indexer-is-deprecated 14 15 people 16 Out[42]: 17 a b c d e 18 Joe 0.125621 -0.059778 0.437543 -1.583435 0.472849 19 Steve 0.855371 0.461129 -0.126290 0.146014 0.373913 20 Wes -2.106125 NaN NaN 0.895130 -1.547358 21 Jim 0.155206 0.202384 0.932044 -1.171872 -1.035313 22 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 red 10 Joe -1.145892 0.538692 11 Steve 0.019724 1.690413 12 Wes 0.895130 -3.653483 13 Jim -0.239828 -0.677722 14 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 red 10 f orange 11 dtype: object 12 13 people.groupby(map_series,axis=1).count() 14 Out[49]: 15 blue red 16 Joe 2 3 17 Steve 2 3 18 Wes 1 2 19 Jim 2 3 20 Travis 2 3
6、通過函數進行分組
任何被當做分組鍵的函數都會在各個索引值上被調用一次,其返回值就會被用作分組名稱。
1 people.groupby(len).sum() 2 Out[50]: 3 a b c d e 4 3 -1.825298 0.142606 1.369587 -1.860177 -2.109822 5 5 0.855371 0.461129 -0.126290 0.146014 0.373913 6 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 e 5 3 one -2.106125 -0.059778 0.437543 -1.583435 -1.547358 6 two 0.155206 0.202384 0.932044 -1.171872 -1.035313 7 5 one 0.855371 0.461129 -0.126290 0.146014 0.373913 8 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 3 10 0 1.641749 2.434674 -0.546666 0.797418 0.530019 11 1 0.084086 0.309776 -0.322581 1.996448 -0.093791 12 2 1.387329 -0.200419 -0.182946 -0.811081 1.081501 13 3 -0.237261 0.288679 -0.057882 0.267184 0.907478 14 15 16 #通過level關鍵字傳入級別編號或名稱 17 hier_df.groupby(level='cty',axis=1).count() 18 Out[59]: 19 cty JP US 20 0 2 3 21 1 2 3 22 2 2 3 23 3 2 3