2017-07-14 276 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