Python 计算2D Numpy数组的行移动平均值时处理np.NaN

Python 计算2D Numpy数组的行移动平均值时处理np.NaN,python,numpy,scipy,moving-average,Python,Numpy,Scipy,Moving Average,我试图根据某个“窗口”(即平均值中包含的行数)和“偏移量”,获得一个数组,该数组包含沿二维numpy数组行的移动平均值。我发现下面的代码效率不高: import numpy as np def f(array, window, offset): x = np.empty(array.shape) x[:,:] = np.NaN for row_num in range(array.shape[0]): first_row = row_num - windo

我试图根据某个“窗口”(即平均值中包含的行数)和“偏移量”,获得一个数组,该数组包含沿二维numpy数组行的移动平均值。我发现下面的代码效率不高:

import numpy as np
def f(array, window, offset):
    x = np.empty(array.shape)
    x[:,:] = np.NaN
    for row_num in range(array.shape[0]):
        first_row = row_num - window - offset
        last_row = row_num - offset + 1
        if first_row >= 0:
            x[row_num] = np.nanmean(array[first_row:last_row], axis=0)
    return x
我已经找到了一个潜在的解决方案,根据我的代码改编如下:

import math
from scipy.ndimage import uniform_filter
def g(array, window, offset):
    return uniform_filter(array, size=(window+1,1), mode='nearest', origin=(math.ceil((window+1)/2-1),0))
但是,此解决方案有3个问题:

  • 首先,我不确定如何实现“偏移”
  • 第二,我不确定它是否真的更有效
  • 第三,也是最重要的一点,当输入数组包含np.nan时,不起作用。找到np.nan的那一刻,它在移动平均线中被拉下,而不是遵循np.nanmean的行为
有没有一个有效的方法来实现我想要的

更新 正如Ehsan所建议的,我已经实现了下面的代码(稍加修改),对于任何大于0的偏移量,它都可以作为我的原始代码使用:

from skimage.util import view_as_windows
def h(array, window, offset):
    return np.vstack(([[np.NaN]*array.shape[-1]]*(window+offset),np.vstack(np.nanmean(view_as_windows(array,(window+1,array.shape[-1])),-2)[:-offset])))
我只是不知道如何使它适用于任何偏移量(特别是,偏移量=0)。此外,此解决方案似乎比原始解决方案耗费更多的时间:

a = np.arange(10*11).reshape(10,11)

%timeit f(a, 5, 2)
%timeit h(a, 5, 2)
>>> 36.6 µs ± 709 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> 67.5 µs ± 2.34 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

我想知道是否有其他更省时的方法

这将为您提供与代码相同的输出,但我认为您可能需要重新考虑
最后一行
定义中额外的
+1
,因为它跳过最后一行,而您的实际窗口大小将是window+1:

from skimage.util import view_as_windows
def f(array, window, offset):
    return np.vstack(([[np.NaN]*array.shape[-1]]*(window+offset),np.vstack(np.nanmean(view_as_windows(array,(window+1,array.shape[-1])),-2)[:array.shape[0]-window-offset])))
样本输出:

a = np.arange(7*6).reshape(7,6)
f(a, 2, 1)
#[[nan nan nan nan nan nan]
# [nan nan nan nan nan nan]
# [nan nan nan nan nan nan]
# [ 6.  7.  8.  9. 10. 11.]
# [12. 13. 14. 15. 16. 17.]
# [18. 19. 20. 21. 22. 23.]
# [24. 25. 26. 27. 28. 29.]]

比较使用
benchit

#@OP's solution
def f1(array, window, offset):
    x = np.empty(array.shape)
    x[:,:] = np.NaN
    for row_num in range(array.shape[0]):
        first_row = row_num - window - offset
        last_row = row_num - offset + 1
        if first_row >= 0:
            x[row_num] = np.nanmean(array[first_row:last_row], axis=0)
    return x
#@Ehsan's solution
def f2(array, window, offset):
    return np.vstack(([[np.NaN]*array.shape[-1]]*(window+offset),np.vstack(np.nanmean(view_as_windows(array,(window+1,array.shape[-1])),-2)[:array.shape[0]-window-offset])))

in_ = {n:[np.arange(n*10).reshape(n,10), 2,2] for n in [10,100,500,1000,4000]}
建议的解决方案f2速度明显加快。您必须注意,大多数矢量化解决方案在较大的阵列上是有效的


为什么最后一行有+1?使用此代码的实际窗口大小为window+1。这就是您想要做的吗?该解决方案对于offset=1非常有效,但是对于offset的其他值,输出数组的大小与输入数组的大小不同。我发现最后使用[:-offset]而不是[:-1]解决了任何不同于0的偏移量的问题-仍然没有找到一种方法使其工作,即使使用offset=0也@Ehsan,从时间消耗的角度来看,这似乎效率较低:
a=np.arange(10*11)。重塑(10,11)
%timeit f(a,5,2)
%timeit h(a,5,2)
>36.6µs±709 ns/循环(平均值±标准偏差7次,每个循环10000次)
<67.5µs±2.34µs/循环(平均值±标准偏差7次,每个循环10000次)
@Mike感谢您抓住了这个错误。请在我的帖子中找到编辑以修复错误,现在它可以处理任何偏移量(包括0)@Mike您用于时间比较的测试阵列很小。矢量化解决方案在较大的阵列上很有效。请在帖子上找到我的比较。这取决于您的阵列大小,哪一个更快。但似乎任何大于10-20大小的测试阵列都会受益于矢量化解决方案。另外,请查看如何接受答案等等非常感谢。