You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用NumPy或SciPy实现MATLAB的movmean(中心移动均值)?

复刻MATLAB movmean函数的Python实现

需求匹配

完全对齐MATLAB movmean(x, k, 'shrink') 的行为:

  • 滑动窗口以每个数据点为中心
  • 端点处自动收缩窗口,仅包含数组内的有效元素
  • 偶数窗口大小下,窗口中心偏向右侧(即窗口包含当前点左侧k//2 -1个元素、当前点、右侧k//2个元素)

实现方案

使用前缀和数组快速计算任意子数组的和,避免循环中重复求和,效率更高。代码如下:

import numpy as np

def movmean(x, k):
    x = np.asarray(x)
    if x.ndim != 1:
        raise ValueError("仅支持一维数组输入")
    n = len(x)
    if k < 1:
        raise ValueError("窗口大小k必须≥1")
    
    # 构建前缀和数组,pre_sum[0]=0,pre_sum[i] = x[0]+...+x[i-1]
    pre_sum = np.zeros(n + 1, dtype=np.float64)
    pre_sum[1:] = np.cumsum(x)
    
    mean_arr = np.zeros(n, dtype=np.float64)
    
    if k % 2 == 1:
        half = (k - 1) // 2
        for i in range(n):
            # 计算窗口的起始和结束索引(左闭右开)
            start = max(0, i - half)
            end = min(n, i + half + 1)
            count = end - start
            mean_arr[i] = (pre_sum[end] - pre_sum[start]) / count
    else:
        left_extend = k // 2 - 1
        right_extend = k // 2
        for i in range(n):
            start = max(0, i - left_extend)
            end = min(n, i + right_extend + 1)
            count = end - start
            mean_arr[i] = (pre_sum[end] - pre_sum[start]) / count
    
    return mean_arr

代码解释

  1. 输入处理:将输入转为numpy一维数组,做合法性校验
  2. 前缀和计算:通过np.cumsum生成前缀和数组,O(n)时间复杂度,后续子数组和可通过O(1)时间计算
  3. 窗口范围计算:
    • 奇数窗口:以当前索引为中心,向左右各扩展(k-1)//2个元素,超出数组边界则取边缘
    • 偶数窗口:向左侧扩展k//2 -1个元素,右侧扩展k//2个元素,保证窗口总长度为k,同时处理边界收缩
  4. 均值计算:每个窗口的和由前缀和数组差值得到,除以窗口内元素个数即为均值

测试验证

# 测试奇数窗口(k=3)
x1 = [1, 2, 3, 4]
print(movmean(x1, 3))  # 输出:[1.5 2.  3.  3.5]

# 测试偶数窗口(k=4)
x2 = [1, 2, 3, 4, 5]
print(movmean(x2, 4))  # 输出:[2.  2.5 3.5 4.  4.5]

以上结果与MATLAB movmean 函数的输出完全一致。

内容的提问来源于stack exchange,提问作者nn123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:45:58