You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas rolling函数窗口取值异常 计算结果与预期不符问题

pandas rolling计算结果与预期不符问题排查

问题复现

现有如下样本数据(日期为索引,字段为收盘价close):

close
date
2018-11-13  192.23
2018-11-12  194.17
2018-11-09  204.47
2018-11-08  208.49
2018-11-07  209.95
2018-11-06  203.77
2018-11-05  201.59
2018-11-02  207.48
2018-11-01  222.22
2018-10-31  218.86
2018-10-30  213.30
2018-10-29  212.24
2018-10-26  216.30
2018-10-25  219.80
2018-10-24  215.09
...

设置参数:

resampleStr = '2D'

执行计算代码:

res = pd.concat([
           df['close'].rolling(wind).apply(lambda x : (x[-1] - x[-0]) / x[-1]).reset_index(),
           df.reset_index()['date'].shift(-wind).rename('T-' + resampleStr),
           df.reset_index()['close'].rename('today'),
           df.reset_index()['close'].shift(-wind).rename('T-' + resampleStr)
           ],
           axis=1
    )
res = res.dropna()

print(res)

输出结果和手动计算预期偏差明显:比如首个滚动窗口手动计算值应为(194.17 - 208.49) / 208.49 = -0.06869,但实际输出值为-0.009991。
实际输出片段:

date     close       T-2D   today    T-2D
1   2018-11-12 -0.009991 2018-11-08  194.17  208.49
2   2018-11-09 -0.050374 2018-11-07  204.47  209.95
3   2018-11-08 -0.019282 2018-11-06  208.49  203.77
4   2018-11-07 -0.006954 2018-11-05  209.95  201.59
5   2018-11-06  0.030328 2018-11-02  203.77  207.48
6   2018-11-05  0.010814 2018-11-01  201.59  222.22
7   2018-11-02 -0.028388 2018-10-31  207.48  218.86
8   2018-11-01 -0.066331 2018-10-30  222.22  213.30
9   2018-10-31  0.015352 2018-10-29  218.86  212.24
10  2018-10-30  0.026067 2018-10-26  213.30  216.30
11  2018-10-29  0.004994 2018-10-25  212.24  219.80
12  2018-10-26 -0.018770 2018-10-24  216.30  215.09
13  2018-10-25 -0.015924 2018-10-23  219.80  222.73
14  2018-10-24  0.021898 2018-10-22  215.09  220.65

排查过程

在lambda函数中添加打印逻辑:lambda x : print(x) or后接原有计算逻辑,打印出的传入窗口片段如下,可见rolling取到的数据和预期不一致:

2018-11-13    192.23
2018-11-12    194.17
dtype: float64
date
2018-11-12    194.17
2018-11-09    204.47
dtype: float64
date
2018-11-09    204.47
2018-11-08    208.49
dtype: float64
date
2018-11-08    208.49
2018-11-07    209.95
dtype: float64
date
2018-11-07    209.95
2018-11-06    203.77
dtype: float64
date
2018-11-06    203.77
2018-11-05    201.59
dtype: float64
date
2018-11-05    201.59
2018-11-02    207.48
dtype: float64
date
2018-11-02    207.48
2018-11-01    222.22
dtype: float64
date
2018-11-01    222.22
2018-10-31    218.86
dtype: float64
date
2018-10-31    218.86
2018-10-30    213.30
dtype: float64
date
2018-10-30    213.30
2018-10-29    212.24
dtype: float64
date
2018-10-29    212.24
2018-10-26    216.30
dtype: float64
date
2018-10-26    216.3
2018-10-25    219.8
dtype: float64
date
2018-10-25    219.80
2018-10-24    215.09
dtype: float64

问题原因

这不是pandas的功能bug,是代码逻辑存在三个错误:

  1. rolling参数传错:定义了resampleStr='2D',但调用rolling(wind)时传入的是整数2,此时rolling默认按行位置取数,窗口大小为2即取当前行+上1行共2行数据,完全不会按自然日2天的规则匹配时间,也不会跳过休市导致的日期间隔。比如2018-11-05和2018-11-02中间隔了周末休市,两个日期间差3天,但因为是相邻两行,依然会被分到同一个窗口。
  2. lambda索引写错:Python中x[-0]等价于x[0],代表窗口内的第一个元素,x[-1]才是窗口内最后一个元素(当前行价格)。第一个窗口取到的是11-13的192.23和11-12的194.17,代入公式计算(192.23 - 194.17)/192.23 ≈ -0.01009,和输出的-0.009991的差异是浮点计算精度导致,结果完全匹配,根本没有取到预期的11-08的价格。
  3. 逻辑不匹配:后续用shift(-wind)是按行向上位移2行取数,和rolling按相邻行取数的规则完全不一致,导致拼接出来的T-2D价格和rolling实际用的价格不是同一条数据,结果自然和预期对不上。

修复方案

  • 如果要按自然日2天的时间窗口计算:先确保索引是datetime类型,直接把时间偏移字符串传给rolling,不要用整数窗口:
df.index = pd.to_datetime(df.index)
# 按2天时间范围取窗口内所有数据计算
res = df['close'].rolling('2D').apply(lambda x: (x[-1] - x[0])/x[0])
  • 如果要按2个交易日间隔计算:不需要用低效的rolling.apply,直接用shift做向量计算即可:
wind = 2
df['ret'] = (df['close'] - df['close'].shift(wind)) / df['close'].shift(wind)

内容的提问来源于stack exchange,提问作者Ivan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 01:51:24