在移动窗口numpy数组上有效地应用函数

Jan*_*egt 5 python performance numpy python-2.7

我有大约100,000个二维数组,我需要应用本地过滤器.两个尺寸均匀,窗口超过2x2,进一步移动2个,因此每个元素都在一个窗口中.输出是相同大小的二进制二维数组,我的过滤器也是二进制2x2.我的过滤器的0部分将映射到0,我的过滤器的部分为1,如果它们具有相同的值则全部映射到1,如果它们不完全相同则映射到0.这是一个例子:

Filter:  0 1     Array to filter:  1 2 3 2    Output:  0 1 0 0
         1 0                       2 3 3 3             1 0 0 0
Run Code Online (Sandbox Code Playgroud)

当然,我可以使用double for循环来做到这一点,但这是非常低效的,并且必须有更好的方法.我读到这个:在numpy上的二维数组上的矢量化移动窗口但是我不确定我将如何应用于我的情况.

Div*_*kar 4

您可以拆分每个子2x2数组,然后重新整形,使每个窗口块成为数组中的一行2Df==1从每一行中,使用 提取出与位置对应的元素boolean indexing。然后,查看每行中所有提取的元素是否相同,从而为我们提供一个掩码。使用此掩码乘以f整形后的最终二进制输出。

因此,假设f作为过滤器数组和A数据数组,遵循这些步骤的矢量化实现将如下所示 -

# Setup size parameters
M = A.shape[0]
Mh = M/2
N = A.shape[1]/2

# Reshape input array to 4D such that the last two axes represent the 
# windowed block at each iteration of the intended operation      
A4D = A.reshape(-1,2,N,2).swapaxes(1,2)

# Determine the binary array whether all elements mapped against 1 
# in the filter array are the same elements or not
S = (np.diff(A4D.reshape(-1,4)[:,f.ravel()==1],1)==0).all(1)

# Finally multiply the binary array with f to get desired binary output
out = (S.reshape(Mh,N)[:,None,:,None]*f[:,None,:]).reshape(M,-1)
Run Code Online (Sandbox Code Playgroud)

样本运行 -

1) 输入:

In [58]: A
Out[58]: 
array([[1, 1, 1, 1, 2, 1],
       [1, 1, 3, 1, 2, 2],
       [1, 3, 3, 3, 2, 3],
       [3, 3, 3, 3, 3, 1]])

In [59]: f
Out[59]: 
array([[0, 1],
       [1, 1]])
Run Code Online (Sandbox Code Playgroud)

2)中间输出:

In [60]: A4D
Out[60]: 
array([[[[1, 1],
         [1, 1]],

        [[1, 1],
         [3, 1]],

        [[2, 1],
         [2, 2]]],


       [[[1, 3],
         [3, 3]],

        [[3, 3],
         [3, 3]],

        [[2, 3],
         [3, 1]]]])

In [61]: S
Out[61]: array([ True, False, False,  True,  True, False], dtype=bool)
Run Code Online (Sandbox Code Playgroud)

3)最终输出:

In [62]: out
Out[62]: 
array([[0, 1, 0, 0, 0, 0],
       [1, 1, 0, 0, 0, 0],
       [0, 1, 0, 1, 0, 0],
       [1, 1, 1, 1, 0, 0]])
Run Code Online (Sandbox Code Playgroud)