import pandas as pd
df = pd.DataFrame({‘key1’:list(‘aabba’),
‘key2’: [‘one’,‘two’,‘one’,‘two’,‘one’],
‘data1’: np.random.randn(5),
‘data2’: np.random.randn(5)})
df123456
grouped=df[‘data1’].groupby(df[‘key1’])
grouped.mean()12
以上的分組鍵均為Series,實際上分組鍵可以是任何長度適當的數組
states=np.array([‘Ohio’,‘California’,‘California’,‘Ohio’,‘Ohio’])
years=np.array([2005,2005,2006,2005,2006])
df[‘data1’].groupby([states,years]).mean()123
df.groupby(‘key1’).mean()1
可以看出沒有key2列,因為df[‘key2’]不是數值數據,所以被從結果中移除。默認情況下,所有數值列都會被聚合,雖然有時可能被過濾為一個子集。
對分組進行迭代
for name, group in df.groupby(‘key1’):
print (name)
print (group)123
可以看出name就是groupby中的key1的值,group就是要輸出的內容。
同理:
for (k1,k2),group in df.groupby([‘key1’,‘key2’]):
print (‘===k1,k2:’)
print (k1,k2)
print (‘===k3:’)
print (group)12345
對group by后的內容進行操作,如轉換成字典
piece=dict(list(df.groupby(‘key1’)))
piece
{‘a’: data1 data2 key1 key2
0 -0.233405 -0.756316 a one
1 -0.232103 -0.095894 a two
4 1.056224 0.736629 a one, ‘b’: data1 data2 key1 key2
2 0.200875 0.598282 b one
3 -1.437782 0.107547 b two}
piece[‘a’]123456789101112
groupby默認是在axis=0上進行分組的,通過設置也可以在其他任何軸上進行分組。
grouped=df.groupby(df.dtypes, axis=1)
dict(list(grouped))
{dtype(‘float64’): data1 data2
0 -0.233405 -0.756316
1 -0.232103 -0.095894
2 0.200875 0.598282
3 -1.437782 0.107547
4 1.056224 0.736629, dtype(‘O’): key1 key2
0 a one
1 a two
2 b one
3 b two
4 a one
123456789101112131415
選取一個或者一組列
對于大數據,很多情況是只需要對部分列進行聚合
df.groupby([‘key1’,‘key2’])[[‘data2’]].mean()
12
通過字典或者series進行分組
people=pd.DataFrame(np.random.randn(5,5),
columns=list(‘abcde’),
index=[‘Joe’,‘Steve’,‘Wes’,‘Jim’,‘Travis’])
people.ix[2:3,[‘b’,‘c’]]=np.nan #設置幾個nan
people123456
已知列的分組關系
mapping={‘a’:‘red’,‘b’:‘red’,‘c’:‘blue’,‘d’:‘blue’,‘e’:‘red’,‘f’:‘orange’}
by_column=people.groupby(mapping,axis=1)
by_column.sum()12345
如果不加axis=1, 則只會出現 a b c d e
Series 也一樣
map_series=pd.Series(mapping)
map_series
a red
b red
c blue
d blue
e red
f orange
dtype: object
people.groupby(map_series,axis=1).count()123456789101112
通過函數進行分組
相較于dic或者Series,python函數在定義分組關系映射時更有創意。任何被當做分組鍵的函數都會在各個索引上被調用一次,其返回值就會被用作分組名稱。假設你按人名的長度進行分組,僅僅傳入len即可
people.groupby(len).sum() a b c d e 3 -1.308709 -2.353354 1.585584 2.908360 -1.267162 5 -0.688506 -0.187575 -0.048742 1.491272 -0.636704 6 0.110028 -0.932493 1.343791 -1.928363 -0.36474512
將函數和數組、列表、字典、Series混合使用也不是問題,因為任何東西都會最終轉換為數組
key_list=[‘one’,‘one’,‘one’,‘two’,‘two’] people.groupby([len,key_list]).sum()1
根據索引級別進行分組
層次化索引最方便的地方就在于他能夠根據索引級別進行聚合。要實現該目的,通過level關鍵字出入級別編號或者名稱即可:
columns=pd.MultiIndex.from_arrays([[‘US’,‘US’,‘US’,‘JP’,‘JP’],[1,3,5,1,3]],names=[‘cty’,‘tenor’])
hier_df=pd.DataFrame(np.random.randn(4,5),columns=columns)
hier_df123
hier_df.groupby(level=‘cty’,axis=1).count()1
數據聚合
調用自定義的聚合函數
面向列的多函數應用
對Series或者DataFrame列的聚合運算實際是使用aggregate或者調用mean,std等方法。下面我們想對不同的列使用不同的聚合函數,或者一次應用多個函數
grouped=tips.groupby([‘sex’,‘smoker’])
grouped_pct=grouped[‘tip_pct’] #tip_pct列
grouped_pct.agg(‘mean’)#對與9-1圖標中描述的統計,可以將函數名直接以字符串傳入
#如果傳入一組函數,得到的df的列名就會以相應的函數命名12345
自動給出的列名辨識度低,如果傳入的是(name, function)元組組成的列表,則各個元組的第一個元素將被用作df的列名
對于df,可以定義一組用于全部列的函數,或在不同的列應用不同的函數
如果想對不同的列應用不同的函數, 具體的辦法是想agg傳入一個從列名映射到函數的字典
只有將多個函數應用到至少一列時,df才能擁有層次化的列
分組級運算和轉換
聚合只是分組運算的一種,它是數據轉換的特列。transform 和apply更牛叉。
transform會將一個函數應用到各個分組,然后將結果放在適當的位置。 如果各分組產生的標量值,則該標量值會被廣播出去。
transform也是有嚴格條件的特殊函數:傳入的函數只能產生兩種結果,要么產生一個可以廣播的標量值(如:np.mean), 要么產生一個相同大小的結果數組。
people=pd.DataFrame(np.random.randn(5,5),
columns=list(‘abcde’),
index=[‘Joe’,‘Steve’,‘Wes’,‘Jim’,‘Travis’])
people
12345
key=[‘one’,‘two’,‘one’,‘two’,‘one’]
people.groupby(key).mean()12
people.groupby(key).transform(np.mean)1
可以看到有很多與表2一樣的值。
def demean(arr):
return arr-arr.mean()
demeaned=people.groupby(key).transform(demean)
demeaned12345
demeaned.groupby(key).mean()1
最一般化的groupby 方法是apply.
tips=pd.read_csv(‘C:UsersecaoyngDesktopwork spacePythonpy_for_analysis_codepydata-book-masterch08 ips.csv’)
tips[:5]12
新生成一列
tips[‘tip_pct’]=tips[‘tip’]/tips[‘total_bill’]
tips[:6]12
根據分組選出最高的5個tip_pct值
def top(df,n=5,column=‘tip_pct’):
return df.sort_index(by=column)[-n:]
top(tips,n=6)123
對smoker分組并應用該函數
tips.groupby(‘smoker’).apply(top)1
多參數版本
tips.groupby([‘smoker’,‘day’]).apply(top,n=1,column=‘total_bill’)1
分位數和桶分析
cut and qcut與groupby結合起來,能輕松的對數據集的桶(bucket)或者分位數(quantile)分析。
frame=pd.DataFrame({‘data1’:np.random.randn(1000),
‘data2’: np.random.randn(1000)})
frame[:5]123
factor=pd.cut(frame.data1,4)
factor[:10]
0 (0.281, 2.00374]
1 (0.281, 2.00374]
2 (-3.172, -1.442]
3 (-1.442, 0.281]
4 (0.281, 2.00374]
5 (0.281, 2.00374]
6 (-1.442, 0.281]
7 (-1.442, 0.281]
8 (-1.442, 0.281]
9 (-1.442, 0.281]
Name: data1, dtype: category
Categories (4, object): [(-3.172, -1.442] 《 (-1.442, 0.281] 《 (0.281, 2.00374] 《 (2.00374, 3.727]]123456789101112131415
def get_stats(group):
return {‘min’:group.min(),‘max’:group.max(),‘count’:group.count(),‘mean’:group.mean()}
grouped=frame.data2.groupby(factor)
grouped.apply(get_stats).unstack()1234
這些都是長度相等的桶,要根據樣本分為數得到大小相等的桶,使用qcut即可。
長度相等的桶:區間大小相等
大小相等的桶:數據點數量相等
grouping=pd.qcut(frame.data1,10,labels=False)#label=false即可值獲取分位數的編號
grouped=frame.data2.groupby(grouping)
grouped.apply(get_stats).unstack()123
評論
查看更多