在numpy中,使用列表和数组进行索引似乎不一致

6

这个问题启发,我正在尝试理解NumPy中的高级索引并建立更直观的理解。

我发现了一个有趣的案例。这是一个数组:

>>> y = np.arange(10)
>>> y
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

如果我将它索引为标量,那当然会得到一个标量:

>>> y[4]
4

使用一个一维整数数组,我会得到另一个一维数组:

>>> idx = [4, 3, 2, 1]
>>> y[idx]
array([4, 3, 2, 1])

如果我使用一个二维整数数组对其进行索引,我会得到什么?
>>> idx = [[4, 3], [2, 1]]
>>> y[idx]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: too many indices for array

哦不!对称性被破坏了。我必须使用3D数组来获取2D数组!

>>> idx = [[[4, 3], [2, 1]]]
>>> y[idx]
array([[4, 3],
       [2, 1]])

什么使得numpy表现出这种行为?
为了使其更有趣,我注意到使用numpy数组进行索引(而不是列表)会按照我的直觉产生行为,并且2D会给我带来2D:
>>> idx = np.array([[4, 3], [2, 1]])
>>> y[idx]
array([[4, 3],
       [2, 1]])

这看起来和我所在的位置不一致。这里的规则是什么?

1
我认为这可能是一个好的起点,尽管我也无法解释其行为。 - GPhilo
3
这个问题在半小时前被提出来,在这里看起来非常相关。 - Divakar
1个回答

3
原因在于将列表作为numpy数组的索引进行解释:列表被解释为元组,而使用元组进行索引会被NumPy解释为多维索引。
就像arr[1, 2]返回元素arr[1][2]一样,arr[[[4, 3], [2, 1]]]arr[[4, 3], [2, 1]]相同,并且根据多维索引规则,将返回元素arr[4, 2]arr[3, 1]
通过添加一个列表,你告诉NumPy你想要沿着第一个维度进行切片,因为最外层的列表被有效地解释为如果你只传递了一个“第一维索引的列表”:arr[[[[4, 3], [2, 1]]]]
文档中可以得知。

Example

From each row, a specific element should be selected. The row index is just [0, 1, 2] and the column index specifies the element to choose for the corresponding row, here [0, 1, 0]. Using both together the task can be solved using advanced indexing:

>>> x = np.array([[1, 2], [3, 4], [5, 6]])
>>> x[[0, 1, 2], [0, 1, 0]]
array([1, 4, 5])

警告

高级索引的定义意味着 x[(1,2,3),]x[(1,2,3)] 本质上是不同的。后者相当于 x[1,2,3],会触发基本选择,而前者会触发高级索引。务必理解这种情况。

在这种情况下,最好使用 np.take:

>>> y.take([[4, 3], [2, 1]])  # 2D array
array([[4, 3],
       [2, 1]])

这个函数 [np.take] 与“fancy”索引(使用数组索引数组)做相同的事情; 然而,如果您需要沿着给定轴的元素,则可以更容易地使用它。

或将索引转换为数组。这样NumPy解释它(array是特殊情况!)作为花式索引,而不是“多维索引”:

>>> y[np.asarray([[4, 3], [2, 1]])]
array([[4, 3],
       [2, 1]])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接