基于ISIN列计算Tone月度滚动均值时遇ValueError问题求助
基于ISIN分组计算Tone列月度滚动平均值的正确实现
问题场景
已构建如下DataFrame,需要按ISIN列分组,计算Tone列的月度滚动平均值(以30天为窗口):
import pandas as pd # 给定数据 tone = [-0.397617, -1.217575, 0.101528, -0.736255, 1.077126] date_x = ["2014-01-01 00:00:00", "2014-02-01 00:00:00", "2014-03-01 00:00:00", "2014-04-01 00:00:00", "2014-05-01 00:00:00"] isin = ["DE0007664005", "DE0007664005", "DE0007664005", "DE0007664005", "DE0007664005"] # 创建DataFrame并转换日期格式 df = pd.DataFrame({'ISIN': isin, 'date_x': date_x, 'Tone': tone}) df['date_x'] = pd.to_datetime(df['date_x'])
尝试以下代码时触发错误:
df.groupby('ISIN')['Tone'].transform(lambda s: s.rolling('30D',on='date_x').mean())
报错信息:
ValueError: invalid on specified as date_x, must be a column (of DataFrame), an Index or None
错误原因
groupby('ISIN')['Tone']返回的是分组后的Series对象,仅包含Tone列数据,不存在date_x列。因此rolling的on='date_x'参数无法找到对应列,导致报错。
两种正确实现方法
方法1:分组后保留完整DataFrame,使用apply计算
通过groupby('ISIN').apply接收每个分组的完整DataFrame,这样可以指定on='date_x'作为时间基准:
# 计算并添加滚动平均列 df['rolling_monthly_tone'] = df.groupby('ISIN').apply( lambda group: group['Tone'].rolling('30D', on='date_x').mean() ).reset_index(level=0, drop=True)
apply传入的group是每个ISIN对应的完整子DataFrame,包含date_x和Tone列reset_index(level=0, drop=True)用于去掉分组产生的ISIN层级,将结果与原DataFrame对齐
方法2:将日期设为索引,简化滚动计算
把date_x设为DataFrame的索引,这样rolling会直接使用索引作为时间窗口的基准,无需指定on参数:
# 1. 设置日期为索引 df = df.set_index('date_x') # 2. 分组计算滚动平均并合并结果 df['rolling_monthly_tone'] = df.groupby('ISIN')['Tone'].rolling('30D').mean().reset_index(level=0, drop=True) # 3. 可选:恢复原索引结构 df = df.reset_index()
结果验证
以示例数据为例,计算结果如下(因日期间隔部分超过30天,部分窗口仅包含当前值):
| date_x | ISIN | Tone | rolling_monthly_tone |
|---|---|---|---|
| 2014-01-01 00:00:00 | DE0007664005 | -0.397617 | -0.397617 |
| 2014-02-01 00:00:00 | DE0007664005 | -1.217575 | -1.217575 |
| 2014-03-01 00:00:00 | DE0007664005 | 0.101528 | -0.558023 |
| 2014-04-01 00:00:00 | DE0007664005 | -0.736255 | -0.317363 |
| 2014-05-01 00:00:00 | DE0007664005 | 1.077126 | 0.170435 |
内容的提问来源于stack exchange,提问作者Mostafa Bouzari
相关产品推荐
相关产品推荐

