大熊猫按累计总数分组

我想在我的熊猫数据框中添加一个累计数列,以便:

姓名 白天 没有
杰克 星期一 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))的组合,但没有用。

164621 次浏览

这样应该可以了,需要 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

你应该用

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

Http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas

另一种方法

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

enter image description here

而不是 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意味着事后不需要调用 set _ index

修改@Dmitry 的回答。这个更简单,适用于熊猫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

数据:

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版本中,熊猫得到了一个新的用于窗口函数的 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,从聚合步骤返回一个数据帧,并使用 assign()为其分配一个新列(每个人的累计和)。

这些链式方法返回一个新的数据框架,因此您需要将它赋值给一个变量(例如 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()
)
)

res