为何Pandas滚动标准差随数据尾部切片大小不同结果各异?
Pandas滚动标准差计算结果不一致的原因分析
当对Series的不同尾部切片(tail(3)、tail(4)、tail(5))应用窗口大小为3的rolling.std()时,出现了结果不一致的情况,尤其是最后一个值差异明显。复现代码及结果如下:
>>> import pandas as pd >>> import numpy as np >>> s = pd.Series(np.random.default_rng(seed=123).random(size=5)) >>> s[1] = 10000000 # 插入一个极大值 >>> s 0 6.823519e-01 1 1.000000e+07 2 2.203599e-01 3 1.843718e-01 4 1.759059e-01 dtype: float64 >>> s.tail(3).rolling(window=3, min_periods=1).std() 2 NaN 3 0.025447 4 0.023604 dtype: float64 >>> s.tail(4).rolling(window=3, min_periods=1).std() 1 NaN 2 7.071068e+06 3 5.773503e+06 4 0.000000e+00 dtype: float64 >>> s.tail(5).rolling(window=3, min_periods=1).std() 0 NaN 1 7.071067e+06 2 5.773502e+06 3 5.773503e+06 4 0.000000e+00 dtype: float64
相比之下,使用rolling.apply(pd.Series.std)时,最后一个结果则保持一致,代码及结果如下:
>>> s.tail(3).rolling(window=3, min_periods=1).apply(pd.Series.std) 2 NaN 3 0.025447 4 0.023604 dtype: float64 >>> s.tail(4).rolling(window=3, min_periods=1).apply(pd.Series.std) 1 NaN 2 7.071068e+06 3 5.773503e+06 4 2.360426e-02 dtype: float64 >>> s.tail(5).rolling(window=3, min_periods=1).apply(pd.Series.std) 0 NaN 1 7.071067e+06 2 5.773502e+06 3 5.773503e+06 4 2.360426e-02 dtype: float64
原因解析
- 数值精度与算法差异
- Pandas内置的
rolling.std()采用Welford增量算法,这种算法通过累积均值和方差来高效计算滚动统计量,但在处理包含极大值的序列时,浮点数的精度限制会导致累积误差。当计算到最后仅包含三个小数值的窗口时,之前窗口中极大值带来的精度偏差被放大,最终错误输出0。 rolling.apply(pd.Series.std)则是对每个窗口的子数据集单独调用标准标准差计算方法,直接基于窗口内所有数据计算,不会受之前窗口累积误差的影响,因此结果准确。
- Pandas内置的
- 切片场景的影响
- 当切片为
tail(3)时,窗口中不包含那个极大值,Welford算法不会受到精度干扰,结果正确; - 当切片包含极大值(
tail(4)、tail(5))时,前面窗口的计算误差传递到最后一个窗口,导致结果偏差。
- 当切片为
内容的提问来源于stack exchange,提问作者KamiKimi 3
相关产品推荐
相关产品推荐

