我们可以将A 与它自己的切片之一连接起来,然后得到那些滑动窗口。要获得这些窗口,我们可以利用基于scikit-image's view_as_windows 的np.lib.stride_tricks.as_strided。然后,将这些窗口与B 相乘以获得最终输出。 More info on use of as_strided based view_as_windows.
因此,我们将有一个像这样的矢量化解决方案 -
In [70]: from skimage.util.shape import view_as_windows
In [71]: A1 = np.concatenate((A,A[:,:-1]),axis=1)
In [74]: view_as_windows(A1,A.shape)[0]*B
Out[74]:
array([[[1, 0, 3],
[0, 0, 6]],
[[2, 0, 1],
[0, 0, 4]],
[[3, 0, 2],
[0, 0, 5]]])
我们还可以利用multi-cores 和numexpr module 作为broadcasted-multiplication 的最后一步,这在更大的阵列上应该会更好。因此,对于示例案例,它将是 -
In [53]: import numexpr as ne
In [54]: w = view_as_windows(A1,A.shape)[0]
In [55]: ne.evaluate('w*B')
Out[55]:
array([[[1, 0, 3],
[0, 0, 6]],
[[2, 0, 1],
[0, 0, 4]],
[[3, 0, 2],
[0, 0, 5]]])
比较建议的两种方法的大型数组的时序 -
In [56]: A = np.random.rand(500,500)
...: B = np.random.rand(500,500)
In [57]: A1 = np.concatenate((A,A[:,:-1]),axis=1)
...: w = view_as_windows(A1,A.shape)[0]
In [58]: %timeit w*B
...: %timeit ne.evaluate('w*B')
1 loop, best of 3: 422 ms per loop
1 loop, best of 3: 228 ms per loop
挤出最好的基于跨步的方法
如果你真的从基于跨步视图的方法中挤出最好的东西,请使用基于 np.lib.stride_tricks.as_strided 的原始方法,以避免 view_as_windows 的功能开销 -
def vaw_with_as_strided(A,B):
A1 = np.concatenate((A,A[:,:-1]),axis=1)
s0,s1 = A1.strides
S = (A.shape[1],)+A.shape
w = np.lib.stride_tricks.as_strided(A1,shape=S,strides=(s1,s0,s1))
return w*B
与基于 @Paul Panzer's array-assignment 的阵列相比,交叉点似乎位于 19x19 形状的阵列 -
In [33]: n = 18
...: A = np.random.rand(n,n)
...: B = np.random.rand(n,n)
In [34]: %timeit vaw_with_as_strided(A,B)
...: %timeit pp(A,B)
10000 loops, best of 3: 22.4 µs per loop
10000 loops, best of 3: 21.4 µs per loop
In [35]: n = 19
...: A = np.random.rand(n,n)
...: B = np.random.rand(n,n)
In [36]: %timeit vaw_with_as_strided(A,B)
...: %timeit pp(A,B)
10000 loops, best of 3: 24.5 µs per loop
10000 loops, best of 3: 24.5 µs per loop
因此,对于小于 19x19 的任何东西,array-assignment 似乎更好,对于大于这些的东西,基于跨步的应该是要走的路。