滑动窗口操作的Numpy Vectorization

Nik*_*il 5 python arrays numpy matrix-multiplication sliding-window

我有以下numpy数组:

arr_1 = [[1,2],[3,4],[5,6]]   # 3 X 2 
arr_2 = [[0.5,0.6],[0.7,0.8],[0.9,1.0],[1.1,1.2],[1.3,1.4]]  # 5 X 2
Run Code Online (Sandbox Code Playgroud)

arr_1显然是一个3 X 2数组,而是arr_2一个5 X 2数组.

现在没有循环,我想以元素方式乘以arr_1和arr_2,以便我将滑动窗口技术(窗口大小3)应用于arr_2.

Example:

Multiplication 1:  np.multiply(arr_1,arr_2[:3,:])

Multiplication 2: np.multiply(arr_1,arr_2[1:4,:])

Multiplication 3: np.multiply(arr_1,arr_2[2:5,:])
Run Code Online (Sandbox Code Playgroud)

我想以某种矩阵乘法形式做到这一点,使它比我目前的解决方案更快,形式如下:

for i in (2):
   np.multiply(arr_1,arr_2[i:i+3,:])  
Run Code Online (Sandbox Code Playgroud)

因此,如果arr_2中的行数很大(数万个数量级),那么这个解决方案并不能很好地扩展.

任何帮助将非常感激.

Div*_*kar 6

我们可以用NumPy broadcasting矢量化方式创建那些滑动窗口索引.然后,我们可以简单的索引arr_2与创建3D阵列,并与执行元素方式乘法2D阵列arr_1,这反过来将带来broadcasting一次.

所以,我们将有一个像这样的矢量化实现 -

W = arr_1.shape[0] # Window size
idx = np.arange(arr_2.shape[0]-W+1)[:,None] + np.arange(W)
out = arr_1*arr_2[idx]
Run Code Online (Sandbox Code Playgroud)

运行时测试并验证结果 -

In [143]: # Input arrays
     ...: arr_1 = np.random.rand(3,2)
     ...: arr_2 = np.random.rand(10000,2)
     ...: 
     ...: def org_app(arr_1,arr_2):
     ...:     W = arr_1.shape[0] # Window size
     ...:     L = arr_2.shape[0]-W+1
     ...:     out = np.empty((L,W,arr_1.shape[1]))
     ...:     for i in range(L):
     ...:        out[i] = np.multiply(arr_1,arr_2[i:i+W,:])
     ...:     return out
     ...: 
     ...: def vectorized_app(arr_1,arr_2):
     ...:     W = arr_1.shape[0] # Window size
     ...:     idx = np.arange(arr_2.shape[0]-W+1)[:,None] + np.arange(W)
     ...:     return arr_1*arr_2[idx]
     ...: 

In [144]: np.allclose(org_app(arr_1,arr_2),vectorized_app(arr_1,arr_2))
Out[144]: True

In [145]: %timeit org_app(arr_1,arr_2)
10 loops, best of 3: 47.3 ms per loop

In [146]: %timeit vectorized_app(arr_1,arr_2)
1000 loops, best of 3: 1.21 ms per loop
Run Code Online (Sandbox Code Playgroud)