MATLAB 在 NumPy/Python 中的平滑实现(n 点移动平均)

Posted

技术标签:

【中文标题】MATLAB 在 NumPy/Python 中的平滑实现(n 点移动平均)【英文标题】:MATLAB's smooth implementation (n-point moving average) in NumPy/Python 【发布时间】:2017-03-19 11:43:30 【问题描述】:

Matlab 的 smooth 函数默认使用 5 点移动平均线对数据进行平滑处理。在 python 中做同样的事情的最好方法是什么? 例如,如果这是我的数据

0
0.823529411764706
0.852941176470588
0.705882352941177
0.705882352941177
0.676470588235294
0.676470588235294
0.500000000000000
0.558823529411765
0.647058823529412
0.705882352941177
0.705882352941177
0.617647058823529
0.705882352941177
0.735294117647059
0.735294117647059
0.588235294117647
0.588235294117647
1
0.647058823529412
0.705882352941177
0.764705882352941
0.823529411764706
0.647058823529412
0.735294117647059
0.794117647058824
0.794117647058824
0.705882352941177
0.676470588235294
0.794117647058824
0.852941176470588
0.735294117647059
0.647058823529412
0.647058823529412
0.676470588235294
0.676470588235294
0.529411764705882
0.676470588235294
0.794117647058824
0.882352941176471
0.735294117647059
0.852941176470588
0.823529411764706
0.764705882352941
0.558823529411765
0.588235294117647
0.617647058823529
0.647058823529412
0.588235294117647
0.617647058823529
0.647058823529412
0.794117647058824
0.823529411764706
0.647058823529412
0.617647058823529
0.647058823529412
0.676470588235294
0.764705882352941
0.676470588235294
0.647058823529412
0.705882352941177
0.764705882352941
0.705882352941177
0.500000000000000
0.529411764705882
0.529411764705882
0.647058823529412
0.676470588235294
0.588235294117647
0.735294117647059
0.794117647058824
0.852941176470588
0.764705882352941

平滑后的数据应该是

0
0.558823529411765
0.617647058823530
0.752941176470588
0.723529411764706
0.652941176470588
0.623529411764706
0.611764705882353
0.617647058823530
0.623529411764706
0.647058823529412
0.676470588235294
0.694117647058824
0.700000000000000
0.676470588235294
0.670588235294118
0.729411764705882
0.711764705882353
0.705882352941177
0.741176470588235
0.788235294117647
0.717647058823529
0.735294117647059
0.752941176470588
0.758823529411765
0.735294117647059
0.741176470588235
0.752941176470588
0.764705882352941
0.752941176470588
0.741176470588235
0.735294117647059
0.711764705882353
0.676470588235294
0.635294117647059
0.641176470588236
0.670588235294118
0.711764705882353
0.723529411764706
0.788235294117647
0.817647058823530
0.811764705882353
0.747058823529412
0.717647058823530
0.670588235294118
0.635294117647059
0.600000000000000
0.611764705882353
0.623529411764706
0.658823529411765
0.694117647058824
0.705882352941176
0.705882352941176
0.705882352941176
0.682352941176471
0.670588235294118
0.676470588235294
0.682352941176471
0.694117647058824
0.711764705882353
0.700000000000000
0.664705882352941
0.641176470588236
0.605882352941177
0.582352941176471
0.576470588235294
0.594117647058824
0.635294117647059
0.688235294117647
0.729411764705882
0.747058823529412
0.803921568627451
0.764705882352941

在 Matlab 中得到这个的语法是

smooth(data)

我想在 python 中做同样的事情,但我找不到任何可以做到这一点的函数。

【问题讨论】:

这个问题和***.com/questions/13728392/…一样吗? @BillBell 我不这么认为 这里有一些其他的例子:scipy-cookbook.readthedocs.io/items/SignalSmooth.html 【参考方案1】:

MATLAB 的 smoooth func 基本上与长度为 5 的滑动窗口的平均相同,只是它处理两端的 2 个元素的方式不同。根据链接的文档,这些边界情况是用这些公式计算的 -

yy = smooth(y) smooths the data in the column vector y ..
The first few elements of yy are given by

yy(1) = y(1)
yy(2) = (y(1) + y(2) + y(3))/3
yy(3) = (y(1) + y(2) + y(3) + y(4) + y(5))/5
yy(4) = (y(2) + y(3) + y(4) + y(5) + y(6))/5
...

因此,要在 NumPy/Python 上复制相同的实现,我们可以使用 NumPy's 1D convolution 来获取滑动窗口总和,然后将它们除以窗口长度,得到平均结果。然后,只需为边界元素附加特殊情况处理的值。

因此,我们将有一个处理通用窗口大小的实现,就像这样 -

def smooth(a,WSZ):
    # a: NumPy 1-D array containing the data to be smoothed
    # WSZ: smoothing window size needs, which must be odd number,
    # as in the original MATLAB implementation
    out0 = np.convolve(a,np.ones(WSZ,dtype=int),'valid')/WSZ    
    r = np.arange(1,WSZ-1,2)
    start = np.cumsum(a[:WSZ-1])[::2]/r
    stop = (np.cumsum(a[:-WSZ:-1])[::2]/r)[::-1]
    return np.concatenate((  start , out0, stop  ))

【讨论】:

非常感谢@Divakar。但是当我尝试使用函数'smooth'时出现以下错误:'AttributeError:'list' object has no attribute 'cumsum'' @rsnaveen 我假设a 是一个 NumPy 数组。修复它以同时处理数组和列表。 非常感谢@Divakar。 如果我复制并过去你的解决方案并在一个 numpy 数组上运行它,我得到 start = np.cumsum(a[:WSZ-1])[::2]/r ValueError: operands could not与形状 (150,) (149,) 一起广播 @ErroriSalvo 它需要一个奇怪的窗口大小,如MATLAB's smooth docs 中所述。它在那里说-"yy = smooth(y,span) sets the span of the moving average to span. span must be odd."。所以,那里的 WSZ 用一个奇数。

以上是关于MATLAB 在 NumPy/Python 中的平滑实现(n 点移动平均)的主要内容,如果未能解决你的问题,请参考以下文章

图像增强基于matlab GSA灰度图像增强含Matlab源码 1172期

NumPy:Python中的强大数学工具

numpy/python 中的加权平均值

Numpy Python 中的哪个对象适合矩阵操作? numpy.array 还是 numpy.matrix? [复制]

计算给定 3 个点及其相对位置的平面的 3D 旋转

从numpy python中的稀疏矩阵生成密集矩阵