常见错误是未指定min_periods,默认要求填满窗口才计算,导致前window-1行全为nan;设min_periods=1可从首项起累计计算,适合平滑;rolling().mean()比rolling().apply(np.mean)更快更稳健;时间窗口需datetimeindex并排序去重;center=true可减少滞后。

pd.DataFrame.rolling() 为什么算出来全是 NaN?
常见错误是没指定 min_periods,尤其当窗口刚启动时,pandas 默认要求填满整个窗口才计算,导致前 window-1 行全为 NaN。比如 df['x'].rolling(5).mean(),前 4 个值一定是 NaN。
- 加
min_periods=1:从第一个值就开始累计平均,适合做平滑曲线 - 不设或设为
min_periods=5:严格等窗口填满才出值,适合统计检验类场景 - 注意:设
min_periods=1后,首项就是原值,第二项是前两项均值,以此类推——这不是“补零”,而是真实滚动计算
rolling().mean() 和 rolling().apply(np.mean) 有啥区别?
表面上结果一样,但底层行为和性能差异明显。前者是 pandas 内置优化路径,后者强制走 Python 层循环,慢一个数量级,还容易在空窗口时报 ValueError: No numeric data to aggregate。
-
rolling(3).mean()支持自动跳过非数值列、处理NaN更稳健 -
rolling(3).apply(np.mean)遇到含NaN的窗口会返回NaN(除非加na_action='ignore'),且对datetime列可能意外报错 - 如果真要自定义逻辑(比如中位数、带权重的均值),优先用
rolling(3).apply(lambda x: np.nanmedian(x)),而不是裸调np.mean
时间序列里用 rolling() 必须先 set_index 吗?
不一定,但不设就默认按行号索引滚动,和你想表达的“过去 7 天”完全对不上。pandas 的 rolling(window='7D') 这种时间窗口,只认 DatetimeIndex。
- 错误写法:
df.rolling('7D').mean()→ 报错Window must be an integer - 正确流程:先
df.set_index('date_col'),再df.index = pd.to_datetime(df.index),最后df.rolling('7D').mean() - 如果日期列有重复或未排序,
rolling('7D')会静默失效——建议加df = df.sort_index().drop_duplicates()预处理
怎么让 rolling 平滑曲线更贴近原始数据趋势?
直接用 .mean() 容易滞后,尤其窗口大时,峰值被压平、拐点延后。这不是 bug,是移动平均的本质特性。
立即学习“Python免费学习笔记(深入)”;
- 试试中心化窗口:
df.rolling(5, center=True).mean(),把均值对齐到窗口中间位置,视觉延迟减半 - 避免用过大窗口(如
rolling(30))平滑日频数据——它实际抹掉了月度波动,不是“平滑”,是“失真” - 若需保边缘信息,别依赖
min_periods=1,改用scipy.signal.savgol_filter(),它用多项式拟合,边界处理更合理










