
本文介绍如何用 numpy 和 pandas 实现灵活、高效的移动平均函数,支持任意窗口大小配置,避免硬编码索引,显著提升性能与可维护性。
本文介绍如何用 numpy 和 pandas 实现灵活、高效的移动平均函数,支持任意窗口大小配置,避免硬编码索引,显著提升性能与可维护性。
在信号处理、时间序列分析和数据平滑任务中,移动平均是一种基础而关键的滤波技术。原始实现中将窗口大小(如 12)硬编码在索引相加表达式中,不仅难以复用,还极易出错且无法扩展。更专业、更高效的做法是利用 NumPy 的切片(arr[i:i+n])和内置聚合函数(如 np.average 或 np.mean),将窗口长度抽象为参数 n,实现通用化设计。
以下是优化后的移动平均函数:
import numpy as np
import pandas as pd
def movingAverageR(data: pd.DataFrame, n: int = 12) -> np.ndarray:
"""
计算一维数据的简单移动平均(SMA),返回长度为 len(data)-n+1 的数组。
Parameters:
-----------
data : pd.DataFrame (单列) 或 pd.Series
输入数据,将被转换为 NumPy 数组
n : int
移动平均窗口大小(必须 ≥ 1)
Returns:
--------
np.ndarray
滤波后的结果数组,长度为 len(data) - n + 1
"""
if n <p>⚠️ <strong>重要注意事项:</strong> </p>
- 原始代码中 range(len(data)-11) 实际对应窗口长度为 12(索引 i 到 i+11 共 12 个元素),但逻辑易混淆;优化版统一用 n 明确语义,并将循环范围设为 len(na)-n+1,确保输出长度正确(标准定义下,n 点移动平均输出长度为 N−n+1)。
- 避免在循环内反复调用 np.append() —— 它每次都会创建新数组,时间复杂度为 O(k²),大幅拖慢性能。改用预分配 np.empty() 并直接赋值,将时间复杂度降至 O(N)。
- 若需更高性能(尤其大数据集),推荐使用 scipy.signal.convolve 或 numpy.lib.stride_tricks.sliding_window_view(NumPy ≥ 1.20):
# 更高性能替代方案(推荐用于生产环境) from numpy.lib.stride_tricks import sliding_window_view def movingAverageFast(data, n=12): na = np.asarray(data).flatten() if len(na)
总结:通过参数化窗口大小、利用数组切片、预分配结果内存及选用合适聚合函数,我们构建了一个健壮、清晰且可扩展的移动平均工具。这不仅是代码风格的改进,更是工程实践中可维护性与性能意识的体现。











