如何高效使用Pandas计算滚动函数?追加新行后的移动平均计算
高效计算追加新行后的Pandas滚动移动平均
首先,对齐你的场景:你已经有一个按分钟频率生成的时间序列,用20窗口的滚动平均完成了基础计算,现在追加了一行新数据,想要高效算出更新后的滚动平均(不管是只取最新值还是更新全序列)。下面给你两种适配不同场景的方案:
1. 简单直接法(适合小数据集)
如果你的数据量不大,直接重新计算整个序列的滚动平均完全没问题,代码和你之前的写法逻辑一致,甚至可以只取最新的那个结果:
# 追加新行(注意:Pandas 2.0+ 推荐用pd.concat替代已弃用的append) ser = pd.concat([ser, new_row]) # 计算滚动平均并取最后一个值(对应新追加行的窗口结果) latest_ma = ser.rolling(window=20).mean().tail(1)
这种方法的好处是代码简单易读,不需要额外逻辑处理,但如果你的数据集非常大(比如百万级以上的行),重新遍历整个序列计算滚动平均会浪费不少计算资源,这时候就轮到增量计算出场了。
2. 增量计算法(适合大数据集,极致高效)
滚动窗口的移动平均本质上就是窗口内所有数据的总和除以窗口大小。当你追加一行新数据时,新的窗口只是把最旧的那个数据移出窗口,再把新数据加进去——所以我们完全可以基于之前的计算结果做增量更新,不用重新跑一遍全序列:
步骤1:提前保存关键值
在追加新行之前,先把原序列最后一个窗口的总和、以及窗口里最旧的数据值存下来:
# 计算原序列的滚动总和(比直接存平均更方便后续计算) rolling_sum = ser.rolling(window=20).sum() # 取最后一个窗口的总和(对应到01:39:00的窗口,包含01:20到01:39的数据) last_window_total = rolling_sum.iloc[-1] # 取出这个窗口里最旧的数据值(01:20:00对应的数值) oldest_val_in_window = ser.loc['2000-01-01 01:20:00']
步骤2:追加新行后计算新的滚动平均
# 追加新行(用pd.concat更稳妥) ser = pd.concat([ser, new_row]) # 新窗口的总和 = 旧窗口总和 - 最旧值 + 新追加的数值 new_window_total = last_window_total - oldest_val_in_window + new_row.iloc[0] # 新的移动平均 = 新总和 / 窗口大小 new_ma = new_window_total / 20
这样得到的new_ma和重新计算整个序列得到的最新滚动平均完全一致,但计算量只是简单的加减除法,数据量越大,效率提升越明显。
额外验证(确保结果正确)
你可以把两种方法的结果对比一下,确认没问题:
# 重新计算的最新滚动平均 recomputed_latest_ma = ser.rolling(window=20).mean().iloc[-1] print(new_ma == recomputed_latest_ma) # 输出True
小提醒:要确保你的时间序列是连续且频率一致的(这里是1分钟),如果中间有缺失的时间点,得先补全再做滚动计算,不然窗口范围会出错哦。
内容的提问来源于stack exchange,提问作者bsdo64
相关产品推荐
相关产品推荐

