如何在Pandas中实现仅对非当前ID的历史值累加求和
问题描述
给定如下DataFrame:
import pandas as pd df = pd.DataFrame({'ID': ['a','b','a','c','b','a','c','b','a','c'], 'Value': [3, 2, 3, 1, 5, 3, 4, 2, 6, 1]})
需要计算Value列的累加和,但仅累加当前行之前所有ID不等于当前ID的Value值。预期结果如下:
df_result = pd.DataFrame({'ID': ['a','b','a','c','b','a','c','b','a','c'], 'Value': [3, 2, 3, 1, 5, 3, 4, 2, 6, 1], 'Sum':[0,3,2,8,7,8,16,14,14,24]})
尝试过np.where和groupby但未得到预期效果,这类动态对比当前ID与之前行ID的累加场景,和常规的固定条件累加不同。
解决方案
可以通过全局累计和减去当前ID的累计和的思路实现,避免逐行循环,效率更优:
- 计算全局的累计和(到当前行的前一行):用
cumsum()后偏移一位,第一行补0。 - 计算每个ID的累计和(到当前行的前一行):用
groupby('ID')['Value'].cumsum()后偏移一位,第一行补0。 - 两者相减就是当前行之前所有非当前ID的Value累加和。
具体代码:
import pandas as pd df = pd.DataFrame({'ID': ['a','b','a','c','b','a','c','b','a','c'], 'Value': [3, 2, 3, 1, 5, 3, 4, 2, 6, 1]}) # 全局累计和,取前一行的总和 global_cumsum = df['Value'].cumsum().shift(fill_value=0) # 各ID的累计和,取前一行同ID的总和 id_cumsum = df.groupby('ID')['Value'].cumsum().shift(fill_value=0) # 计算目标Sum列 df['Sum'] = global_cumsum - id_cumsum print(df)
运行结果与预期一致:
ID Value Sum 0 a 3 0 1 b 2 3 2 a 3 2 3 c 1 8 4 b 5 7 5 a 3 8 6 c 4 16 7 b 2 14 8 a 6 14 9 c 1 24
思路说明
global_cumsum:第n行的值是前n-1行所有Value的总和,比如第1行的global_cumsum是第0行的3,第2行是前两行的3+2=5。id_cumsum:第n行的值是前n-1行中与当前行ID相同的Value总和,比如第2行ID为a,id_cumsum是第0行的3;第4行ID为b,id_cumsum是第1行的2。- 两者相减后,正好得到前n-1行中非当前ID的Value总和,完全匹配需求。
内容的提问来源于stack exchange,提问作者Syhaa
相关产品推荐
相关产品推荐

