繁体   English   中英

了解 Numpy 多维数组索引

[英]Understanding Numpy Multi-dimensional Array Indexing

请谁能解释一下这三个索引操作之间的区别:

y = np.arange(35).reshape(5,7)

# Operation 1
y[np.array([0,2,4]),1:3]
# Operation 2
y[np.array([0,2,4]), np.array([[1,2]])]
# Operation 3
y[np.array([0,2,4]), np.array([[1],[2]])]

我不明白的是:

  • 为什么操作 2 不工作而操作 1 工作正常?
  • 为什么操作 3 有效,但返回了我期望的转置(即操作 1 的结果)?

根据numpy参考:

如果索引数组的形状不同,则会尝试将它们广播为相同的形状。 如果它们不能广播到相同的形状,则会引发异常。

好的,所以这意味着我不能这样做:

y[np.array([0,2,4]), np.array([1,2])]

但是 numpy 参考也说明了操作 1:

实际上,切片被转换为索引数组 np.array([[1,2]]) (shape (1,2)) 与索引数组一起广播以生成形状为 (3,2) 的结果数组.

那么为什么我不能这样做:

y[np.array([0,2,4]), np.array([[1,2]])]

我收到错误:

IndexError:形状不匹配:索引数组无法与形状一起广播 (3,) (1,2)

In [1]: import numpy as np; y = np.arange(35).reshape(5,7)

操作 1

In [2]: y[np.array([0,2,4]), 1:3]
Out[2]: 
array([[ 1,  2],
       [15, 16],
       [29, 30]])

这里我们混合了高级索引(使用数组)和基本索引(使用切片),只有一个高级索引。 根据参考

[a] 单个高级索引可以例如替换切片并且结果数组将相同 [...]

正如以下代码所示,这是正确的:

In [3]: y[::2, 1:3]
Out[3]: 
array([[ 1,  2],
       [15, 16],
       [29, 30]])

Out[2]Out[3]的唯一区别是前者是y数据的副本(高级索引总是产生一个副本),而后者是一个与y共享相同内存的视图(基本索引总是产生视图)。

因此,在操作 1 中,我们通过np.array([0,2,4])选择了行,通过1:3了列。

操作2

In [4]: y[np.array([0,2,4]), np.array([[1,2]])]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-4-bf9ee1361144> in <module>()
----> 1 y[np.array([0,2,4]), np.array([[1,2]])]

IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (3,) (1,2) 

这失败了,并且无法理解为什么我们首先必须意识到这个示例中索引的本质与操作 1 有着根本的不同。现在我们只有高级索引(并且不止一个高级索引)。 这意味着索引数组必须具有相同的形状或至少具有与广播兼容的形状。 让我们来看看形状。

In [5]: np.array([0,2,4]).shape
Out[5]: (3,)
In [6]: np.array([[1,2]]).shape
Out[6]: (1, 2)

这意味着广播机制将尝试组合这两个数组:

np.array([0,2,4])  (1d array):     3
np.array([[1,2]])  (2d array): 1 x 2
Result             (2d array): 1 x F

最后一行末尾的F表示形状不兼容。 这就是操作 2 中IndexError的原因。

操作3

In [7]: y[np.array([0,2,4]), np.array([[1],[2]])]
Out[7]: 
array([[ 1, 15, 29],
       [ 2, 16, 30]])

同样,我们只有高级索引。 现在让我们看看形状是否兼容:

In [8]: np.array([0,2,4]).shape
Out[8]: (3,)
In [9]: np.array([[1],[2]]).shape
Out[9]: (2, 1)

这意味着广播将像这样工作:

np.array([0,2,4])     (1d array):     3
np.array([[1],[2]])   (2d array): 2 x 1
Result                (2d array): 2 x 3

所以现在广播工作了! 由于我们的索引数组被广播到一个 2x3 数组,这也将是结果的形状。 所以它也解释了与操作 1 不同的结果的形状。

要获得操作 1 中形状为 3x2 的结果,我们可以这样做

In [10]: y[np.array([[0],[2],[4]]), np.array([1, 2])]
Out[10]: 
array([[ 1,  2],
       [15, 16],
       [29, 30]])

现在广播机制是这样工作的:

np.array([[0],[2],[4]])  (2d array): 3 x 1
np.array([1, 2])         (1d array):     2
Result                   (2d array): 3 x 2

给出一个 3x2 数组。 而不是np.array([1, 2])

In [11]: y[np.array([[0],[2],[4]]), np.array([[1, 2]])]
Out[11]: 
array([[ 1,  2],
       [15, 16],
       [29, 30]])

会因为

np.array([[0],[2],[4]])  (2d array): 3 x 1
np.array([[1, 2]])       (2d array): 1 x 2
Result                   (2d array): 3 x 2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM