Python - 通过每 n 行取 n 个连续行来重塑矩阵

问题描述

在 stackoverflow 上有很多关于使用 NumPy 重构矩阵的问题。我发现 one 与我要实现的目标密切相关。但是,这个答案对于我的应用程序来说不够通用。所以我们来了。

我有一个包含数百万行(形状 m x n)的矩阵,如下所示:

[[0,0],[1,1,1],[2,2,2],[3,3,3],[4,4,4],[5,5,5],[6,6,6],[7,7,7],[...]]

从这里我想去一个形状 m/2 x 2n 就像它可以在下面看到的那样。为此,必须每 n 行取 n 个连续行(在本例中 n = 2)。然后将连续获取的行的块水平堆叠到未触及的行。在这个例子中,这意味着:

  1. 前两行保持原样。
  2. 取第 2 行和第 3 行,将它们水平连接到第 0 行和第 1 行。
  3. 将第 6 行和第 7 行水平连接到第 4 行和第 5 行。这个串联的块然后成为第二行和第三行。
  4. ...
[[0,[...]]

如何使用 Numpy 最有效地(就可能的计算时间而言)做到这一点?使用 Numba 加快进程是否有意义?还是没有什么可以加速的?

解决方法

假设您的数组的长度可以被 4 整除,那么在创建正确的索引以选择结果数组的“左”和“右”部分的行后,您可以使用 numpy.hstack 来执行此操作的一种方法:

import numpy 
# Create the array
N = 1000*4
a = np.hstack([np.arange(0,N)[:,None]]*4) #shape (4000,4)
a
array([[   0,0],[   1,1,1],[   2,2,2],...,[3997,3997,3997],[3998,3998,3998],[3999,3999,3999]])

left_idx = np.array([np.array([0,1]) + 4*i for i in range(N//4)]).reshape(-1)
right_idx = np.array([np.array([2,3]) + 4*i for i in range(N//4)]).reshape(-1)

r = np.hstack([a[left_idx],a[right_idx]]) #shape (2000,8)
r
array([[   0,3,3],[   4,4,6,6],[3993,3993,3995,3995],[3996,3996,3999]])
,

这是您链接中 swapaxes 答案的应用。

In [11]: x=np.array([[0,...:  [1,...:  [2,...:  [3,...:  [4,4],...:  [5,5,5],...:  [6,...:  [7,7,7]])

通过重塑将数组分成“组”,保持列数 (4) 不变。

In [17]: x.reshape(2,4)
Out[17]: 
array([[[[0,[1,1]],[[2,[3,3]]],[[[4,[5,5]],[[6,[7,7]]]])

交换 2 个中间维度,重新组合行:

In [18]: x.reshape(2,4).transpose(0,3)
Out[18]: 
array([[[[0,[2,2]],[[1,[6,6]],[[5,7]]]])

然后回到目标形状。这最后一步创建了原始副本(前面的步骤是 view):

In [19]: x.reshape(2,3).reshape(4,8)
Out[19]: 
array([[0,[4,7]])

很难概括这一点,因为有不同的重新排列块的方法。例如我的第一次尝试产生:

In [16]: x.reshape(4,4).transpose(1,2).reshape(4,8)
Out[16]: 
array([[0,7]])