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]])
这里我们混合了高级索引(使用数组)和基本索引(使用切片),只有一个高级索引。根据reference
[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 根本不同。现在我们只有高级索引(并且不止一个高级索引)。这意味着索引数组必须具有相同的形状或至少与broadcasting 兼容的形状。让我们看看形状。
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