你可以通过结合
np.reshape
和
np.swapaxes
来实现,像这样 -
def extract_blocks(a, blocksize, keep_as_view=False):
M,N = a.shape
b0, b1 = blocksize
if keep_as_view==0:
return a.reshape(M//b0,b0,N//b1,b1).swapaxes(1,2).reshape(-1,b0,b1)
else:
return a.reshape(M//b0,b0,N//b1,b1).swapaxes(1,2)
可以看到,使用它有两种方式 - 开启(默认)或关闭 keep_as_view
标志。使用 keep_as_view = False
,我们将交换轴进行重塑,并得到最终输出为3D
的形状; 而使用 keep_as_view = True
,我们将保持其为4D
的形状,并且这将是输入数组的视图,因此在运行时几乎免费。我们稍后会用一个样例案例运行来验证。
样例案例
让我们使用一个样例输入数组,如下所示 -
In [94]: a
Out[94]:
array([[2, 2, 6, 1, 3, 6],
[1, 0, 1, 0, 0, 3],
[4, 0, 0, 4, 1, 7],
[3, 2, 4, 7, 2, 4],
[8, 0, 7, 3, 4, 6],
[1, 5, 6, 2, 1, 8]])
现在让我们使用一些块大小进行测试。让我们使用一个块大小为(2,3)
,并分别打开和关闭视图标志 -
In [95]: extract_blocks(a, (2,3))
Out[95]:
array([[[2, 2, 6],
[1, 0, 1]],
[[1, 3, 6],
[0, 0, 3]],
[[4, 0, 0],
[3, 2, 4]],
[[4, 1, 7],
[7, 2, 4]],
[[8, 0, 7],
[1, 5, 6]],
[[3, 4, 6],
[2, 1, 8]]])
In [48]: extract_blocks(a, (2,3), keep_as_view=True)
Out[48]:
array([[[[2, 2, 6],
[1, 0, 1]],
[[1, 3, 6],
[0, 0, 3]]],
[[[4, 0, 0],
[3, 2, 4]],
[[4, 1, 7],
[7, 2, 4]]],
[[[8, 0, 7],
[1, 5, 6]],
[[3, 4, 6],
[2, 1, 8]]]])
使用keep_as_view=True
验证view
In [20]: np.shares_memory(a, extract_blocks(a, (2,3), keep_as_view=True))
Out[20]: True
让我们来看看在一个大数组上的表现,并验证之前讨论的几乎免费的运行时间声明 -
In [42]: a = np.random.rand(2000,3000)
In [43]: %timeit extract_blocks(a, (2,3), keep_as_view=True)
1000000 loops, best of 3: 801 ns per loop
In [44]: %timeit extract_blocks(a, (2,3), keep_as_view=False)
10 loops, best of 3: 29.1 ms per loop
a
是你的输入,你可以直接使用a[2*j:2*j+2, 2*k:2*k+2]
。这是你的意思吗? - Warren Weckesser