2017-07-14 246 views
2

我正在寻找一种方法来计算三维Numpy数组中每个给定值的均值,其中20个值直接位于上方,20个值位于正下方的行中。这与我之前提出的一个问题类似(Taking minimum value of each entry +- 10 rows either side in numpy array),但计算41个值的平均值而不是21个值的最小值。如何高效地计算python中的移动平均值

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

有没有使用均匀过滤器的方法,或者是否有其他方法可以实现这一点?

谢谢。

编辑: Numpy数组的尺寸为20x3200x18,所以我正在寻找一个相对有效的解决方案。

回答

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

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是一个窗口柜台,让你避免错误的边缘

+0

感谢丹尼尔。我应该提到阵列很大(20x3200x18),所以我不确定旋转运算对我来说是最好的解决方案。 – JGraham353

+0

对于大型数组,'scipy.signal.fftconvolve'更快。请注意,此函数执行循环卷积运算,这将使您在边缘处出现与“scipy.signal.convolve”不同的行为。 – Michael