受到this other question的启发,我试图将我的思绪包裹在NumPy中advanced indexing,并对其工作方式有更直观的理解。
我发现了一个有趣的案例。这是一个数组:
>>> y = np.arange(10)
>>> y
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
如果我将其标记为标量,我当然会得到一个标量:
>>> y[4]
4
使用1D整数数组,我得到另一个1D数组:
>>> idx = [4, 3, 2, 1]
>>> y[idx]
array([4, 3, 2, 1])
所以,如果我用2D整数数组对它进行索引,我得到......我得到了什么?
>>> 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]])
这与我所处的地方看起来不一致。这里的规则是什么?
答案 0 :(得分:2)
原因是将列表解释为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您希望沿第一个维度进行切片,因为最外面的列表被有效地解释为您只传入了第一个维度的一个&#34;索引列表&#34;: arr[[[[4, 3], [2, 1]]]]
。
实施例
从每一行开始,应选择一个特定元素。行索引只是[0,1,2],列索引指定要为相应行选择的元素,此处为[0,1,0]。将两者结合使用可以使用高级索引解决任务:
>>> x = np.array([[1, 2], [3, 4], [5, 6]]) >>> x[[0, 1, 2], [0, 1, 0]] array([1, 4, 5])
and:
警告
高级索引的定义意味着
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
]与“花式”索引(使用数组索引数组)做同样的事情;但是,如果您需要沿给定轴的元素,则可以更容易使用。
或者将索引转换为数组。就这样NumPy解释它(array
是特殊的!)作为花哨的索引,而不是&#34;多维索引&#34;:
>>> y[np.asarray([[4, 3], [2, 1]])]
array([[4, 3],
[2, 1]])