滑动窗口操作的 Numpy 矢量化
Posted
技术标签:
【中文标题】滑动窗口操作的 Numpy 矢量化【英文标题】:Numpy Vectorization of sliding-window operation 【发布时间】:2017-01-07 01:13:57 【问题描述】:我有以下 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
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,:])
我想以某种矩阵乘法形式执行此操作,以使其比我当前的解决方案更快:
for i in (2):
np.multiply(arr_1,arr_2[i:i+3,:])
因此,如果 arr_2 中的行数很大(大约数万),则此解决方案的扩展性并不是很好。
任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:我们可以使用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]
运行时测试和验证结果-
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
【讨论】:
你先生是个巫师。这个广播概念让我大吃一惊!谢谢!【参考方案2】:这是测试as_strided
和Divakar广播速度的好案例。
In [281]: %%timeit
...: out=np.empty((L,W,arr1.shape[1]))
...: for i in range(L):
...: out[i]=np.multiply(arr1,arr2[i:i+W,:])
...:
10 loops, best of 3: 48.9 ms per loop
In [282]: %%timeit
...: idx=np.arange(L)[:,None]+np.arange(W)
...: out=arr1*arr2[idx]
...:
100 loops, best of 3: 2.18 ms per loop
In [283]: %%timeit
...: arr3=as_strided(arr2, shape=(L,W,2), strides=(16,16,8))
...: out=arr1*arr3
...:
1000 loops, best of 3: 805 µs per loop
Create Numpy array without enumerating array 了解这些方法的更多比较。
【讨论】:
以上是关于滑动窗口操作的 Numpy 矢量化的主要内容,如果未能解决你的问题,请参考以下文章