如何在DataFrame中实现每月末重置为1的月度累计乘积(CumReturn列)
解决DataFrame分组内月度累计乘积并重置的问题
需求说明
需要在DataFrame df 中新建一列 CumReturn,实现:
- 按
ID1分组 - 对
Return列进行月度累计乘积计算 - 当
EndMonth == 1(月末标记)时,累计乘积重置为1,次月重新开始累计
原代码问题分析
你尝试的代码:
df['CumReturn'] = np.where(df['EndMonth'] == 1, 1, df['Return'].groupby('ID1').cumprod())
问题在于 groupby('ID1').cumprod() 是对整个ID1分组的所有行做累积乘积,没有识别EndMonth的重置信号,导致跨月后不会重新开始计算,而是延续之前的累积结果。
解决方案
核心思路是在每个ID1分组内,基于EndMonth生成子分组标识,让每个月度的行属于独立的子分组,再对每个子分组计算累积乘积。
完整代码
import pandas as pd import numpy as np # 复现示例数据 df1 = pd.DataFrame({ 'Date':['2023-01-30', '2023-01-30', '2023-01-31', '2023-01-31', '2023-02-01', '2023-02-01', '2023-02-02', '2023-02-02'], 'EndMonth':[0, 0, 1, 1, 0, 0, 0, 0], 'ID1':['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B'], 'Return':[0.95, 0.98, 1.01, 1.02, 1.05, 0.92, 0.97, 0.99]}) df1 = df1.set_index('Date') # 步骤1:在每个ID1分组内生成重置分组标识 df1['reset_group'] = df1.groupby('ID1')['EndMonth'].cumsum() # 步骤2:按ID1+reset_group分组计算累积乘积 df1['CumReturn'] = df1.groupby(['ID1', 'reset_group'])['Return'].cumprod() # 步骤3:将EndMonth==1的行重置为1 df1['CumReturn'] = np.where(df1['EndMonth'] == 1, 1, df1['CumReturn']) # 可选:删除中间列reset_group df1 = df1.drop('reset_group', axis=1) print(df1)
运行结果
EndMonth ID1 Return CumReturn Date 2023-01-30 0 A 0.95 0.9500 2023-01-30 0 B 0.98 0.9800 2023-01-31 1 A 1.01 1.0000 2023-01-31 1 B 1.02 1.0000 2023-02-01 0 A 1.05 1.0500 2023-02-01 0 B 0.92 0.9200 2023-02-02 0 A 0.97 1.0185 2023-02-02 0 B 0.99 0.9108
代码解释
- 生成reset_group:
df1.groupby('ID1')['EndMonth'].cumsum()会在每个ID1组内,每次遇到EndMonth==1时累加1,这样每个月度的行被划分为独立的子分组(比如ID1=A的1月行属于reset_group=0,2月行属于reset_group=1)。 - 子分组累积乘积:通过
['ID1', 'reset_group']多级分组,确保每个月度的累积计算只在当前子组内进行,不会跨月延续。 - 重置月末值:用
np.where将EndMonth==1的行强制设为1,符合需求中月末重置的规则。
内容的提问来源于stack exchange,提问作者fjurt
相关产品推荐
相关产品推荐

