如何在python中有效地计算移动平均线

时间:2017-07-14 10:07:11

标签: python arrays numpy scipy mean

我正在寻找一种计算3d Numpy数组中每个给定值的平均值的方法,其中直接在上面的行中有20个值,在下面的行中有20个值。这类似于我之前提出的问题(Taking minimum value of each entry +- 10 rows either side in numpy array),但是计算了41个值的平均值而不是最小值21个值。

我尝试过使用Scipy's uniform 1d filter,但是这个模式没有正确处理接近数组边缘的值的模式。阵列外部的窗口不应包括在平均值计算中(即在阵列的底部/顶部位置,平均值应取自边缘值和上面/下面的20行)。

有没有办法使用均匀滤波器,还是有替代方法可以达到这个目的?

感谢。

修改 Numpy阵列的尺寸为20x3200x18,因此我一直在寻找一种相对有效的解决方案。

2 个答案:

答案 0 :(得分:1)

您可以使用scipy.signal.convolve执行此操作。

import scipy.signal as sig

def windowed_mean(arr, n):
    dims = len(arr.shape)
    s = sig.convolve(arr, np.ones((2*n+1,)*dims), mode='same')
    d = sig.convolve(np.ones_like(arr), np.ones((2*n+1,)*dims), mode='same')
    return s/d

基本上,s是窗口总和,d是窗口计数器,因此您可以避免边缘出错

答案 1 :(得分:1)

如果你真的在寻找性能,你可以利用cumsum只需计算一次总和,这应该会使实现速度快40倍。

请参阅下面的示例。如果没有您的确切数据和参考实现,我无法验证这是否符合您的要求,但它本质上应该是正确的。

import numpy as np
import matplotlib.pyplot as plt

arr = np.random.rand(20, 3200, 18)
n = 20

cumsum = np.cumsum(arr, axis=1)

means_lower = cumsum[:, :n, :] / np.arange(1, n + 1)[None, :, None]
means_middle = (cumsum[:, 2 * n:, :] - cumsum[:, :-2 * n , :]) / (2 * n)
means_upper = (cumsum[:, -1, :][:, None, :] - cumsum[:, -n - 1:-1, :]) / np.arange(n, 0, -1)[None, :, None]

means = np.concatenate([means_lower, means_middle, means_upper], axis=1)

x = np.arange(3200)

plt.plot(x, means[0, :, 0])

enter image description here

相关问题