[英]Multi index groupby count including NaN values in pandas and, calculate percentage by single groupby
我有一個 df,如下所示。
df:
Country Player
Arg Messi
Bra Neymar
Arg NaN
Arg Messi
Arg Aguero
Arg Messi
Bra Ronaldo
Spain Xavi
Spain NaN
Spain NaN
Bra Rivaldo
Spain Iniesta
Bra NaN
Spain Xavi
其中 NaN 代表信息不可用。 從上面的 df 中,我想執行多個 groupby 計數,如下所示。
預期輸出:
Country Player Counts Percentage_of_country
Arg NaN 1 20
Arg Messi 3 60
Arg Aguero 1 20
Bra Neymar 1 25
Bra NaN 1 25
Bra Ronaldo 1 25
Bra Rivaldo 1 25
Spain NaN 2 40
Spain Xavi 2 40
Spain Iniesta 1 20
我試過下面的代碼:
df2 = df.groupby(['Country', 'Player']).size().reset_index(name='counts')
df2['prcntg'] = df2['counts']/df2.groupby('Country')['counts'].transform('sum')
df2
首先按Country
和Player
對數據幀進行分組,然后調用size
進行計數,並調用to_frame
傳遞列名以從中創建數據幀。 您還需要傳遞dropna=True
因為您想包含NaN
。
之后,您可以按level=0
對計數進行分組,然后調用tranform
以獲取級別的總和,並將計數除以該值。 如果需要,您可以最后調用reset_index
。
count=df.groupby(['Country', 'Player'], dropna=False).size().to_frame('Counts')
count['Percentage_of_country']=100*count/count.groupby(level=0).transform('sum')
輸出:
Counts Percentage_of_country
Country Player
Arg Aguero 1 20.0
Messi 3 60.0
NaN 1 20.0
Bra Neymar 1 25.0
Rivaldo 1 25.0
Ronaldo 1 25.0
NaN 1 25.0
Spain Iniesta 1 20.0
Xavi 2 40.0
NaN 2 40.0
dropna
參數是在 pandas版本 1.1.0 中引入的,因此如果您使用的版本早於該版本,您可以先嘗試將NaN
值替換為其他值,然后在執行所需操作后恢復為NaN
。
df['Player'] = df['Player'].fillna('#!Missing!#') #replace NaN by #!Missing!#'
count=df.groupby(['Country', 'Player']).size().to_frame('Counts')
count['Percentage_of_country']=100*count/count.groupby(level=0).transform('sum')
count.reset_index(inplace=True)
count['Player'] = count['Player'].replace({'#!Missing!#':float('nan')})
另一種方法,真正在單個groupby
產生所有結果如下:
定義一個輔助函數來計算百分比:
使用dropna=False
保留NaN
值:
f = lambda x: x.size / df.groupby('Country', dropna=False).size()[x.iloc[0]] * 100
第一個size
函數返回['Country', 'Player']
組下的計數,而第二個size
函數,僅分組在Country
下,返回更大組下的計數。
然后,利用DataFrameGroupBy.aggregate()
的named aggregation
:
(df.groupby(['Country', 'Player'], dropna=False)
.agg(counts=('Player', 'size'),
prcntg=('Country', f))
)
結果:
counts prcntg
Country Player
Arg Aguero 1 20.0
Messi 3 60.0
NaN 1 20.0
Bra Neymar 1 25.0
Rivaldo 1 25.0
Ronaldo 1 25.0
NaN 1 25.0
Spain Iniesta 1 20.0
Xavi 2 40.0
NaN 2 40.0
如果您收到錯誤TypeError: groupby() got an unexpected keyword argument 'dropna'
,則可能您的 Pandas 版本早於1.1.0版本。 自此版本起支持此 dropna 參數,它允許您保留 NaN 計數。 可能您應該考慮升級 Pandas 以獲得更豐富的 Pandas 功能。
如果您目前無法升級,解決方法是將 Player 列中的 NaN 替換為其他一些文本,例如。 字符串 '_NaN' 或分組前的一些特殊詞。 如果需要,您可以在分組后恢復其值。 示例代碼如下:
import numpy as np
df['Player'] = df['Player'].fillna('_NaN') # Set `NaN` values to string `_NaN`
# Main processing with all results produced in a single `groupby`:
f = lambda x: x.size / df.groupby('Country').size()[x.iloc[0]] * 100
df_out = (df.groupby(['Country', 'Player'], as_index=False)
.agg(counts=('Player', 'size'),
prcntg=('Country', f))
)
df_out['Player'] = df_out['Player'].replace('_NaN', np.nan) # restore `NaN` values
結果:
print(df_out)
Country Player counts prcntg
0 Arg Aguero 1 20.0
1 Arg Messi 3 60.0
2 Arg NaN 1 20.0
3 Bra Neymar 1 25.0
4 Bra Rivaldo 1 25.0
5 Bra Ronaldo 1 25.0
6 Bra NaN 1 25.0
7 Spain Iniesta 1 20.0
8 Spain Xavi 2 40.0
9 Spain NaN 2 40.0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.