簡體   English   中英

Pandas groupby 累計和

[英]Pandas groupby cumulative sum

我想在我的 Pandas dataframe 中添加一個累積總和列,以便:

姓名
傑克 周一 10
傑克 周二 20
傑克 周二 10
傑克 周三 50
吉爾 周一 40
吉爾 周三 110

變成:

Jack | Monday     | 10  | 10
Jack | Tuesday    | 30  | 40
Jack | Wednesday  | 50  | 90
Jill | Monday     | 40  | 40
Jill | Wednesday  | 110 | 150

我嘗試了df.groupbydf.agg(lambda x: cumsum(x))的各種組合,但無濟於事。

這應該可以,需要groupby()兩次:

df.groupby(['name', 'day']).sum() \
  .groupby(level=0).cumsum().reset_index()

解釋:

print(df)
   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   20
2  Jack    Tuesday   10
3  Jack  Wednesday   50
4  Jill     Monday   40
5  Jill  Wednesday  110

# sum per name/day
print( df.groupby(['name', 'day']).sum() )
                 no
name day           
Jack Monday      10
     Tuesday     30
     Wednesday   50
Jill Monday      40
      Wednesday  110

# cumulative sum per name/day
print( df.groupby(['name', 'day']).sum() \
         .groupby(level=0).cumsum() )
                 no
name day           
Jack Monday      10
     Tuesday     40
     Wednesday   90
Jill Monday      40
     Wednesday  150

由第一個總和產生的數據幀由'name''day'索引。 你可以通過打印看到它

df.groupby(['name', 'day']).sum().index 

在計算累積總和時,您希望通過'name' ,對應於第一個索引(級別 0)。

最后,使用reset_index使名稱重復。

df.groupby(['name', 'day']).sum().groupby(level=0).cumsum().reset_index()

   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   40
2  Jack  Wednesday   90
3  Jill     Monday   40
4  Jill  Wednesday  150

這適用於熊貓 0.16.2

In[23]: print df
        name          day   no
0      Jack       Monday    10
1      Jack      Tuesday    20
2      Jack      Tuesday    10
3      Jack    Wednesday    50
4      Jill       Monday    40
5      Jill    Wednesday   110
In[24]: df['no_cumulative'] = df.groupby(['name'])['no'].apply(lambda x: x.cumsum())
In[25]: print df
        name          day   no  no_cumulative
0      Jack       Monday    10             10
1      Jack      Tuesday    20             30
2      Jack      Tuesday    10             40
3      Jack    Wednesday    50             90
4      Jill       Monday    40             40
5      Jill    Wednesday   110            150

修改@Dmitry 的回答。 這更簡單,適用於 Pandas 0.19.0:

print(df) 

 name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   20
2  Jack    Tuesday   10
3  Jack  Wednesday   50
4  Jill     Monday   40
5  Jill  Wednesday  110

df['no_csum'] = df.groupby(['name'])['no'].cumsum()

print(df)
   name        day   no  no_csum
0  Jack     Monday   10       10
1  Jack    Tuesday   20       30
2  Jack    Tuesday   10       40
3  Jack  Wednesday   50       90
4  Jill     Monday   40       40
5  Jill  Wednesday  110      150

你應該使用

df['cum_no'] = df.no.cumsum()

http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.cumsum.html

另一種方法

import pandas as pd
df = pd.DataFrame({'C1' : ['a','a','a','b','b'],
           'C2' : [1,2,3,4,5]})
df['cumsum'] = df.groupby(by=['C1'])['C2'].transform(lambda x: x.cumsum())
df

在此處輸入圖片說明

而不是df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum() (見上文)你也可以做一個df.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()

  • df.groupby(by=['name','day']).sum()實際上只是將兩列移動到 MultiIndex
  • as_index=False意味着您之后不需要調用 reset_index

數據.csv:

name,day,no
Jack,Monday,10
Jack,Tuesday,20
Jack,Tuesday,10
Jack,Wednesday,50
Jill,Monday,40
Jill,Wednesday,110

代碼:

import numpy as np
import pandas as pd

df = pd.read_csv('data.csv')
print(df)
df = df.groupby(['name', 'day'])['no'].sum().reset_index()
print(df)
df['cumsum'] = df.groupby(['name'])['no'].apply(lambda x: x.cumsum())
print(df)

輸出:

   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   20
2  Jack    Tuesday   10
3  Jack  Wednesday   50
4  Jill     Monday   40
5  Jill  Wednesday  110
   name        day   no
0  Jack     Monday   10
1  Jack    Tuesday   30
2  Jack  Wednesday   50
3  Jill     Monday   40
4  Jill  Wednesday  110
   name        day   no  cumsum
0  Jack     Monday   10      10
1  Jack    Tuesday   30      40
2  Jack  Wednesday   50      90
3  Jill     Monday   40      40
4  Jill  Wednesday  110     150

從 1.0 版開始,pandas 為 window 功能獲得了新的 api。

具體來說,早先取得的成就
df.groupby(['name'])['no'].apply(lambda x: x.cumsum())
或者
df.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()

現在變成
df.groupby(['name'])['no'].expanding().sum()

我發現所有與窗口相關的功能都比 groupby+level 操作更直觀

盡管學習使用 groupby 對於一般用途很有用。
請參閱文檔: https://pandas.pydata.org/docs/user_guide/window.html

如果你想寫一個單線(也許你想將方法傳遞到管道中),你可以通過首先將groupby方法的as_index參數設置為 False 以從聚合步驟返回 dataframe 並使用assign()來實現為其分配一個新列(每個人的累積總和)。

這些鏈接的方法返回一個新的 dataframe,因此您需要將其分配給一個變量(例如agg_df )以便以后能夠使用它。

agg_df = (
    # aggregate df by name and day
    df.groupby(['name','day'], as_index=False)['no'].sum()
    .assign(
        # assign the cumulative sum of each name as a new column
        cumulative_sum=lambda x: x.groupby('name')['no'].cumsum()
    )
)

資源

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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