簡體   English   中英

多索引 groupby 計數,包括 pandas 中的 NaN 值,並按單個 groupby 計算百分比

[英]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

首先按CountryPlayer對數據幀進行分組,然后調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM