我想对一个NumPy n×n数组进行切片。我想提取该数组的m行和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]])
第一个问题是它很难阅读,尽管我可以接受这一点。如果有人有更好的解决方案,我当然想听听。
另一件事是我读到了on a forum,用数组索引数组迫使NumPy复制所需的数组,因此当处理大型数组时,这可能会成为一个问题。为什么会这样/这种机制是如何工作的?
发布于 2010-11-24 00:07:26
正如斯文提到的,x[[[0],[2]],[1,3]]
将返回与1和3列匹配的0和2行,而x[[0,2],[1,3]]
将以数组形式返回值x0,1和x2,3。
对于我给出的第一个例子,有一个有用的函数numpy.ix_
。您可以使用x[numpy.ix_([0,2],[1,3])]
执行与我的第一个示例相同的操作。这可以使您不必输入所有这些额外的括号。
发布于 2010-11-23 23:31:14
要回答这个问题,我们必须看看在Numpy中索引多维数组是如何工作的。首先,假设您的问题中有数组x
。分配给x
的缓冲区将包含16个从0到15的升序整数。如果您访问一个元素,例如x[i,j]
,NumPy必须计算出此元素相对于缓冲区开头的内存位置。这是通过计算有效的i*x.shape[1]+j
(并与一个整数的大小相乘得到实际的内存偏移量)来实现的。
如果通过像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]
的内存偏移量将产生正确的结果。
但是对于像z=x[[1,3]]
这样的东西,NumPy应该做些什么呢?如果原始缓冲区用于z
,步长机制将不允许正确的索引。从理论上讲,NumPy可以添加一些比跨度更复杂的机制,但这会使元素访问相对昂贵,不知何故,这违背了数组的整体概念。此外,视图将不再是真正的轻量级对象。
在the NumPy documentation on indexing中对此进行了深入的介绍。
哦,几乎忘记了你的实际问题:下面是如何让多个列表的索引按预期的方式工作:
x[[[1],[3]],[1,3]]
这是因为索引数组是broadcasted到一个共同的形状。当然,对于这个特定的示例,您也可以使用基本的切片:
x[1::2, 1::2]
发布于 2010-11-23 23:19:01
我不认为x[[1,3]][:,[1,3]]
很难读懂。如果你想更清楚地表达你的意图,你可以这样做:
a[[1,3],:][:,[1,3]]
我不是切片方面的专家,但通常情况下,如果你试图切片到一个数组中,并且值是连续的,你会得到一个步幅值发生变化的视图。
例如,在您的输入33和34中,尽管您得到的是2x2数组,但步长是4。因此,当您索引下一行时,指针会移动到内存中的正确位置。
显然,这种机制不能很好地适用于索引数组的情况。因此,numpy将不得不进行复制。毕竟,许多其他矩阵数学函数依赖于大小、步长和连续的内存分配。
https://stackoverflow.com/questions/4257394
复制相似问题