NumPy 2d数组的切片,或者如何从nxn数组(n>m)中提取MXM子矩阵?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (20)

我想分割一个NumPy nxn数组。我想提取一个任意选择该数组的m行和列(即在行/列数中没有任何模式),使其成为一个新的MXM数组。对于这个例子,假设数组是4x4,我想从其中提取一个2x2数组。

这是我们的数组:

from numpy import *
x = range(16)
x = reshape(x,(4,4))

print x
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]

要删除的行和列是相同的。最简单的情况是,当我想提取一个2x2子矩阵时,它位于开头或结尾,即:

In [33]: x[0:2,0:2]
Out[33]: 
array([[0, 1],
       [4, 5]])

In [34]: x[2:,2:]
Out[34]: 
array([[10, 11],
       [14, 15]])

但是,如果我需要移除另一个行/列的混合物,怎么办?如果我需要删除第一行和第三行,从而提取子矩阵,该怎么办?[[5,7],[13,15]]是吗?行/行可以任意组合。我在某个地方读到,我只需要使用数组/索引列表对数组和列进行索引,但这似乎不起作用:

In [35]: x[[1,3],[1,3]]
Out[35]: array([ 5, 15])

我找到了一种方法,那就是:

    In [61]: x[[1,3]][:,[1,3]]
Out[61]: 
array([[ 5,  7],
       [13, 15]])

使用数组进行索引的数组迫使NumPy复制所需的数组,因此在处理大型数组时,这可能会成为一个问题。为什么这个机制是这样/如何运作的?

提问于
用户回答回答于

要回答这个问题,我们必须看看多维数组在Numpy中是如何工作的。首先假设你有一个数组x从你的问题。分配给x将包含从0到15的16个升序整数。如果您访问一个元素,比如x[i,j],NumPy必须计算该元素相对于缓冲区开头的内存位置。这是通过实际计算来完成的。i*x.shape[1]+j(并与int的大小相乘以获得实际内存偏移量)。

如果通过基本切片提取子数组,如y = x[0:2,0:2],生成的对象将与x但是如果你y[i,j]是吗?NumPy不能使用i*y.shape[1]+j将偏移量计算到数组中,因为属于y在内存中不是连续的。

NumPy通过引入大步计算用于访问的内存偏移量时x[i,j],实际上计算的是i*x.strides[0]+j*x.strides[1](这已经包括了整数大小的因子):

x.strides
(16, 4)

何时y如上面所示,NumPy不会创建新的缓冲区,但它是吗?创建引用相同缓冲区的新数组对象(否则为y就等于x)新数组对象将具有不同的形状。x可能会有不同的起始偏移量进入缓冲区,但将与x(至少在这种情况下):

y.shape
(2,2)
y.strides
(16, 4)

这样,计算内存偏移量y[i,j]会得到正确的结果。

但是NumPy应该做些什么z=x[[1,3]]是吗?如果使用原始缓冲区,那么大步机制将不允许正确的索引。z.NumPy理论添加一些比大步更复杂的机制,但这将使元素访问相对昂贵,不知何故无视数组的整个概念。此外,视图不再是一个真正的轻量级对象了。

下面是如何使多个列表的索引像预期的那样工作:

x[[[1],[3]],[1,3]]

也可以使用基本切片:

x[1::2, 1::2]
用户回答回答于

正如斯文提到的,x[[[0],[2]],[1,3]]将返回与1列和3列匹配的0行和2行。x[[0,2],[1,3]]将返回值x。0,1和x2,3在一个数组中。

我给出的第一个例子有一个有用的功能,numpy.ix_.您可以执行与我的第一个示例相同的操作x[numpy.ix_([0,2],[1,3])]这可以避免你不得不进入所有这些额外的括号。

扫码关注云+社区