Pandas 分组累计求和
我想在我的Pandas数据框中添加一列累计和,这样:
姓名 | 日期 | 数量 |
---|---|---|
杰克 | 星期一 | 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.groupby
和 df.agg(lambda x: cumsum(x))
,但都没有成功。
8 个回答
9
你可以用 df.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()
来替代 df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum()
(见上面)。
df.groupby(by=['name','day']).sum()
实际上只是把这两列变成了一个多重索引(MultiIndex)。as_index=False
的意思是你不需要在之后再调用 reset_index。
13
你应该使用
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
60
这个在 pandas 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
83
对@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
148
这样做就可以了,需要用到 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