使用'30D'滚动计算时出现'window必须为非负整数'错误的求助
解决非每日间隔分组数据的30天滚动求和问题
问题原因
你遇到的ValueError: window must be an integer 0 or greater,本质是因为在transform中传入的x是分组后的Value列,它的索引不是datetime类型,无法识别'30D'这种时间窗口参数,因此要求窗口必须为整数。
解决方案
要实现按分组计算每个日期过去30天的滚动求和,需确保每个分组的索引为datetime格式的日期列,再应用时间窗口的滚动计算。以下是修正后的代码:
import pandas as pd import numpy as np # 创建非每日间隔的测试数据 np.random.seed(42) date_rng = pd.date_range(start='2022-01-01', end='2023-12-31', freq='10D') data = {'Date': np.random.choice(date_rng, size=30), 'Group': np.random.choice(['A', 'B'], size=30), 'Value': np.random.randint(1, 30, size=30)} df = pd.DataFrame(data) # 按分组+日期排序,确保计算逻辑正确 df = df.sort_values(by=['Group', 'Date']).reset_index(drop=True) df['Date'] = pd.to_datetime(df['Date']) # 定义分组内计算滚动30天求和的函数 def rolling_30d_sum(group): # 将分组的Date设为索引,才能使用时间窗口 group = group.set_index('Date') # 计算滚动30天求和,min_periods=1确保即使不足30天也计算 group['RollingSum_Last30Days'] = group['Value'].rolling(window='30D', min_periods=1).sum() # 恢复原索引,方便合并回原DataFrame return group.reset_index() # 应用函数到每个分组 df = df.groupby('Group').apply(rolling_30d_sum).reset_index(drop=True) print(df.head())
关键说明
- 先按
Group和Date排序:确保每个分组内的数据按时间顺序排列,滚动计算结果才准确。 - 分组内设置日期为索引:只有当索引是datetime类型时,
rolling(window='30D')才能识别时间窗口,计算过去30天内的所有数据求和。 - 使用
apply代替transform:apply可处理整个分组的DataFrame,方便修改索引并添加计算列,最后合并回原结构。
也可以用更简洁的写法,直接在分组后操作整个DataFrame:
df = df.sort_values(['Group', 'Date']) df['RollingSum_Last30Days'] = df.groupby('Group').apply( lambda g: g.set_index('Date')['Value'].rolling('30D', min_periods=1).sum() ).reset_index(level=0, drop=True)
该写法通过reset_index(level=0, drop=True)去掉分组索引,直接将结果匹配回原DataFrame的行,效果与上述函数一致。
内容的提问来源于stack exchange,提问作者Richard Dixon
相关产品推荐
相关产品推荐

