用numpy.convolve实现移动平均需设weights=np.ones(w)/w、mode='valid'并确保输入为float;多维数组应改用sliding_window_view;pandas方案引入冗余依赖且nan处理不一致。

用 numpy.convolve 实现最简移动平均
直接调用 numpy.convolve 是最轻量、最可控的方式,尤其适合一维数组。它本质是做滑动窗口卷积,把窗口权重设为全 1 再归一化,就等价于移动平均。
常见错误是忽略 mode 参数导致输出长度不对:mode='valid' 输出比原数组短 window_size - 1,而 mode='same' 会补零对齐但首尾值不准。
- 推荐用
mode='valid',避免边界污染;如需等长结果,后续再手动填充(比如用首尾值或线性插值) - 窗口权重必须是
np.ones(window_size) / window_size,不能漏除法——否则算出来是移动和,不是移动平均 - 输入数组要是
float类型,否则整数数组卷积后仍是整数,小数部分被截断
import numpy as np arr = np.array([1, 2, 3, 4, 5, 6], dtype=float) window = 3 weights = np.ones(window) / window ma = np.convolve(arr, weights, mode='valid') # → [2., 3., 4., 5.]
处理多维数组时别直接套用 convolve
numpy.convolve 只支持 1D,对二维数组(比如按行求每行的移动平均)会报错 ValueError: object too deep for desired array。
正确做法是用 numpy.lib.stride_tricks.sliding_window_view(NumPy ≥ 1.20),它能生成视图而非拷贝,内存友好且天然支持多维。
- 对二维数组
data每行做窗口=5 的移动平均:sliding_window_view(data, window_shape=5, axis=-1).mean(axis=-1) -
axis必须显式指定,否则默认在第 0 轴滑动,容易弄反方向 - 该函数返回的是只读视图,若后续要修改结果,得先
.copy()
from numpy.lib.stride_tricks import sliding_window_view data = np.array([[1,2,3,4,5], [10,20,30,40,50]]) ma_rows = sliding_window_view(data, 3, axis=-1).mean(axis=-1) # shape: (2, 3)
为什么不用 pandas.Series.rolling().mean()
虽然 pandas 写起来更短,但它引入了额外依赖、隐式类型转换(比如自动把 int64 转成 float64),而且底层仍调用 NumPy 运算——纯 NumPy 场景下没必要绕一圈。
更关键的是:当数组含 NaN 时,pandas 默认跳过缺失值(skipna=True),而原生 NumPy 的 convolve 或 sliding_window_view 遇到 NaN 会传染整个窗口结果为 NaN。行为不一致,容易埋坑。
- 如果数据确定无缺失值,NumPy 方案更快、更透明
- 如果需要
NaN容忍,改用scipy.ndimage.uniform_filter1d(支持mode='nearest'等边界处理) - 别在 NumPy 项目里为省几行代码加 pandas 依赖
性能和边界处理的实际取舍
移动平均本身计算简单,瓶颈通常在内存访问模式和边界填充策略。用 sliding_window_view 比手动切片快,但比 convolve 多一次 mean 计算;而 uniform_filter1d 在大数组上最快,但需要 scipy。
- 小数组(convolve,代码少、易调试
- 中大数组 + 需要等长输出:优先
sliding_window_view+ 手动补边(如np.pad) - 实时流式数据或严格边界要求(如信号处理):选
scipy.ndimage.uniform_filter1d,它支持镜像/周期等填充模式
边界永远是最容易被忽略的部分——convolve 的 'valid' 虽安全,但丢数据;'same' 补零又扭曲趋势。真要生产用,得根据业务决定首尾怎么填,而不是依赖默认值。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











