numpy 如何排序数组切片索引?
Posted
技术标签:
【中文标题】numpy 如何排序数组切片索引?【英文标题】:How does numpy order array slice indices? 【发布时间】:2015-01-21 13:14:02 【问题描述】:我有一个形状为 (28,8,20) 的 np.array data
,我只需要其中的某些条目,所以我要分片:
In [41]: index = np.array([ 5, 6, 7, 8, 9, 10, 11, 17, 18, 19])
In [42]: extract = data[:,:,index]
In [43]: extract.shape
Out[43]: (28, 8, 10)
到目前为止一切都很好,一切都应该如此。但现在我只想查看第一行最后一个索引上的前两个条目:
In [45]: extract[0,:,np.array([0,1])].shape
Out[45]: (2, 8)
等等,应该是 (8,2)。它切换了索引,即使我上次切片时它没有!根据我的理解,下面的行为应该是一样的:
In [46]: extract[0,:,:2].shape
Out[46]: (8, 2)
...但这正是我想要的!不过,只要我有一个 3D 数组,这两种方法似乎都是等效的:
In [47]: extract[:,:,np.array([0,1])].shape
Out[47]: (28, 8, 2)
In [48]: extract[:,:,:2].shape
Out[48]: (28, 8, 2)
如果我想要的不仅仅是前两个条目,而是一个不规则的列表,我该怎么办?我当然可以在操作后转置矩阵,但这似乎非常违反直觉。 我的问题的一个更好的解决方案是这样(尽管可能有一个更优雅的解决方案):
In [64]: extract[0][:,[0,1]].shape
Out[64]: (8, 2)
这将我们带入实际
问题:
我想知道这种行为的原因是什么?谁决定这就是它应该如何工作的人可能比我更了解编程,并认为这在某种程度上是一致的,而我完全错过了。除非我有办法理解它,否则我可能会一直在这个问题上大发雷霆。
【问题讨论】:
The docs 用于高级索引(使用数组作为索引)承认这种行为“可能有点难以理解”。我不敢尝试完全掌握这种索引的复杂性。可以这么说,使用数组而不是切片(即[0, 1]
而不是:2
)会触发不同类型的索引行为,并且组合不同类型的索引(单个整数、切片、数组)可以快速带您进入陌生的领域。
【参考方案1】:
这是(高级)部分索引的情况。有2个索引数组,1个切片
如果索引子空间是分开的(通过切片对象),那么广播的索引空间是第一个,然后是x的切片子空间。
http://docs.scipy.org/doc/numpy-1.8.1/reference/arrays.indexing.html#advanced-indexing
高级索引示例说明,当ind_1
、ind_2
可广播子空间为shape (2,3,4)
时:
但是,x[:,ind_1,:,ind_2] 的形状为 (2,3,4,10,30,50),因为在索引子空间中没有明确的放置位置,因此它被附加到开始。总是可以使用 .transpose() 将子空间移动到任何需要的地方。
换句话说,此索引与x[:, ind_1][[:,ind_2]
不同。这 2 个数组共同操作以定义 (2,3,4)
子空间。
在您的示例中,extract[0,:,np.array([0,1])]
被理解为意味着选择一个(2,)
子空间([0] 和 [0,1] 共同作用,而不是顺序作用),并以某种方式将其与中间维度结合起来。
更详细的例子是extract[[1,0],:,[[0,1],[1,0]]]
,它产生一个(2,2,8)
数组。这是第一个和最后一个维度的(2,2)
子空间,加上中间的一个。另一方面,X[[1,0]][:,:,[[0,1],[1,0]]]
生成 (2,8,2,2)
,分别从第一个和最后一个维度中选择。
关键区别在于索引选择是顺序操作还是联合操作。 `[...][...] 语法已经可用于顺序操作。高级索引为您提供了一种联合索引的方法。
【讨论】:
如果我理解正确,那么我的代码中的0
将被视为一个单项列表,因此两个 lists
将一起广播(提供一个 1x2 数组),因此索引移到前面。
... 因为没有“明确”的其他地方可以放置它。使用广播的整个想法根本不是切片而是索引,我可以在索引中放置任意数组并获得原始数组内容的各种排列 - 这似乎是有道理的,尽管它看起来更多因此也将[:,:,[0,1]]
的索引放在首位。
这意味着我应该使用单独的索引 ([...][...]
) 来明确我的意图——谢谢!【参考方案2】:
你是对的,这很奇怪。我只能在这里冒险猜测。我认为这与a[[0,1],[0,1],[0,1]].shape
是(2,)
而不是(2,2,2)
以及a[0,1,[0,1,2]]
的真正含义是a[[0,0,0],[1,1,1],[0,1,2]]
的计算结果为array([a[0,1,0],a[0,1,1],a[0,1,2]])
有关。也就是说,您可以并行遍历每个维度的列表即索引,广播长度为一的列表和标量以匹配最长的。
从概念上讲,这将使您的extract[0,:,[0,1]]
等同于extract[[0,0],[slice(None),slice(None)],[0,1]]
(但是,如果您手动指定它,则不接受该语法)。遍历索引后,将评估为array([extract[0,slice(None),0],extract[0,slice(None),1])
。每个内部提取都评估为形状 (8,)
数组,因此完整结果是形状 (2,8)
。
所以总结一下,我认为广播的副作用是使所有维度都有一个相同长度的索引列表,这导致:
也被广播。这是我的假设,但我还没有研究过 numpy
是如何做到这一点的内部工作原理。也许专家会给出更好的解释。
这个假设不能解释为什么extract[:,:,[0,1]]
不会导致相同的行为。我不得不假设只有前导“:”的情况是特殊情况以避免参与列表索引逻辑。
【讨论】:
以上是关于numpy 如何排序数组切片索引?的主要内容,如果未能解决你的问题,请参考以下文章