直接用np.mean遍历窗口慢是因为python循环反复切片并调用解释器,产生大量内存分配;而np.cumsum前缀和差分可向量化计算所有窗口均值,效率更高。

为什么直接用 np.mean 遍历窗口会慢?
因为 Python 循环调用 np.mean 对每个子数组求均值,本质是反复切片 + 解释器开销。哪怕数组只有 10⁵ 元素,窗口大小为 100,也要创建 10⁵−99 个新视图,触发大量内存分配和拷贝 —— 这不是 NumPy 的优势路径。
用 np.cumsum 做前缀和差分(最通用且零依赖)
核心思路:窗口平均 = (前缀和[i+w] − 前缀和[i]) / w。只要能算出前缀和,所有窗口均值一步到位,全程纯向量化。
-
arr是一维ndarray,长度为n - 先算
cumsum = np.cumsum(arr, dtype=np.float64)(显式指定dtype防溢出) - 构造输出数组:
result = np.empty(n - w + 1) - 填值:
result[:] = (cumsum[w:] - cumsum[:-w]) / w
注意:cumsum[:-w] 和 cumsum[w:] 长度一致,广播自然对齐。比 scipy.signal.convolve 更轻量,且不引入额外依赖。
用 numpy.lib.stride_tricks.sliding_window_view(NumPy ≥ 1.20)
这是语义最直白的方案,但默认返回视图而非拷贝 —— 如果后续要修改窗口内容,得加 .copy(),否则原数组会被意外改写。
- 调用:
from numpy.lib.stride_tricks import sliding_window_view - 生成窗口:
windows = sliding_window_view(arr, window_shape=w) - 求均值:
result = windows.mean(axis=-1)(axis=-1确保按最后一个维度即窗口维度计算)
缺点:内存占用随窗口增大线性增长(虽然底层是视图,但 .mean() 会触发临时数组),w 超过 10³ 时可能比前缀和慢;优点是支持多维数组(如图像滑窗),且逻辑清晰易调试。
边界处理和 NaN 安全性怎么加?
原始方法默认丢弃不足窗口长度的尾部。如果需要补零、补均值或保持长度,得手动 pad;若输入含 NaN,np.mean 默认返回 NaN,必须显式用 np.nanmean 替代。
- 补零填充:
arr_padded = np.pad(arr, (w-1, 0), mode='constant', constant_values=0),再套前缀和法 - 忽略 NaN:
result = np.nanmean(windows, axis=-1),但sliding_window_view遇到全NaN窗口仍返回NaN - 性能提醒:启用
nanmean后无法使用前缀和加速,只能回退到逐窗口计算或改用scipy.ndimage.uniform_filter1d
真正容易被忽略的是数据类型溢出 —— np.int32 数组做前缀和极易上溢,务必提前转 float64 或用 dtype=object(不推荐)。窗口越大,越要检查 cumsum.max() 是否接近类型上限。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











