numpy数组中的索引混淆
我对numpy数组的索引逻辑感到很困惑,尤其是当数组有多个维度的时候。这里有个例子:
import numpy as np
A = np.arange(18).reshape(3,2,3)
[[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]],
[[12, 13, 14],
[15, 16, 17]]])
这个例子给我一个形状为(3,2,3)的数组,咱们就叫它们(x,y,z)来方便讨论。现在我想要一个数组B,里面的元素来自数组A,条件是x=0和2,y=0和1,z=1和2。就像这样:
array([[[ 1, 2],
[4, 5]],
[[13, 14],
[16, 17]]])
我天真地以为
B=A[[0,2],[0,1],[1,2]]
这样就能实现。可是它给出的结果是
array([ 2, 104])
而且不管用。
A[[0,2],:,:][:,:,[1,2]]
最后这个方法可以实现我的需求。但我还是想知道我最开始的尝试哪里出错了?还有,做我想做的事情的最佳方法是什么?
3 个回答
如果你想要
A[(0,2),:,1:]
用这个方式来选择你想要的内容,比如说你想要的索引、行和列
array([[[ 1, 2],
[ 4, 5]],
[[13, 14],
[16, 17]]])
我推荐一个高级教程,它讲解了各种索引方法:NumPy MedKit
一旦你理解了如何强大地索引数组(以及这些方法如何结合使用),你就会明白其中的道理。如果你第一次尝试是有效的,那么这可能会和其他一些索引技巧发生冲突(减少你在其他情况下的选择)。
在你的例子中,你可以利用第三个索引覆盖一个连续的范围:
A[[0,2],:,1:]
你也可以使用
A[np.ix_([0,2],[0,1],[1,2])]
这在更一般的情况下很有用,当后面的索引不是连续的时候。np.ix_
只是构建了三个索引数组。
正如Sven在他的回答中指出的,这种特定情况下有一种更有效的方法(使用视图而不是复制的版本)。
编辑:正如Sven指出的,我的回答包含了一些错误,我已经删除了这些错误。我仍然认为他的回答更好,但不幸的是我现在无法删除我的回答。
在NumPy中,有两种索引方式:基本索引和高级索引。基本索引使用切片的元组来进行索引,它不会复制数组,而是创建一个调整过的视图。而高级索引则使用索引的列表或数组,并会复制数组。
你的第一次尝试
B = A[[0, 2], [0, 1], [1, 2]]
使用了高级索引。在高级索引中,所有的索引列表会先被广播到相同的形状,然后这个形状会用于输出数组。在这个例子中,它们已经具有相同的形状,所以广播并没有做任何事情。输出数组也会有两个条目。输出数组的第一个条目是通过使用三个列表的所有第一个索引得到的,第二个条目则是通过使用所有第二个索引得到的:
B = numpy.array([A[0, 0, 1], A[2, 1, 2]])
你的第二种方法
B = A[[0,2],:,:][:,:,[1,2]]
是可行的,但效率不高。它使用了两次高级索引,所以你的数据会被复制两次。
为了用高级索引得到你想要的结果,你可以使用
A[np.ix_([0,2],[0,1],[1,2])]
正如nikow所指出的。这只会复制数据一次。
在你的例子中,你完全可以不复制数据,只用基本索引就能实现:
B = A[::2, :, 1:2]