与花哨的索引混淆(对于非花哨的人)

Confusion with Fancy indexing (for non-fancy people)

让我们假设一个多维数组

import numpy as np
foo = np.random.rand(102,43,35,51)

我知道那些最后的维度代表一个 2D space (35,51),我想索引 的一系列行 =]列 假设我想要第 0 列的第 8 行到第 30 行 根据我对索引的理解,我应该调用

foo[0][0][8::30][0]

尽管知道我的数据(与此处使用的随机数据不同),但这不是我所期望的

我可以试试这个确实有效但看起来很荒谬

foo[0][0][[8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30],0]

现在我可以在 this documentation 中找到我也可以使用 类似于:

foo[0][0][[8,30],0]

这只给我第 8 行和第 30 行的值 而这个:

foo[0][0][[8::30],0]

报错

File "<ipython-input-568-cc49fe1424d1>", line 1
foo[0][0][[8::30],0]
                ^
SyntaxError: invalid syntax

我不明白为什么不能在这里传递::参数。那么在索引语法中指示范围的方法是什么?

所以我想我的总体问题是这种语法的正确 pythonic 等价物是什么:

foo[0][0][[8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30],0]

而不是

foo[0][0][8::30][0]

尝试

foo[0, 0, 8:30, 0]

foo[0][0] 部分与 foo[0, 0, :, :] 相同,选择二维数组 (35 x 51)。但是 foo[0][0][8::30] 选择了这些行的子集

考虑在二维数组上使用 0::30 时会发生什么:

In [490]: np.zeros((35,51))[0::30].shape
Out[490]: (2, 51)

In [491]: np.arange(35)[0::30]
Out[491]: array([ 0, 30])

30 是切片的 step,而不是 stop 值。

最后一个 [0] 然后选择这些行中的第一行。最终结果与 foo[0,0,0,:].

相同

在大多数情况下,使用逗号语法索引多个维度会更好。如果您想要前 30 行,请使用 0:30,而不是 0::30(这是基本的切片符号,适用于列表和数组)。

至于:

foo[0][0][[8::30],0]

简化为x[[8::30], 0]。 Python 解释器接受 [1:2:3, 0],将其翻译成 tuple(slice(1,2,3), 0) 并将其传递给 __getitem__ 方法。但是冒号语法在非常特定的上下文中被接受。解释器将内部括号组视为一个列表,那里不接受冒号。

foo[0,0,[1,2,3],0]

没问题,因为内括号是一个列表,而 numpy getitem 可以处理这些。

numpy 有一个工具可以将切片表示法转换为数字列表。如果它仍然令人困惑,请尝试一下:

In [495]: np.r_[8:30]
Out[495]: 
array([ 8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
       25, 26, 27, 28, 29])
In [496]: np.r_[8::30]
Out[496]: array([0])
In [497]: np.r_[8:30:2]
Out[497]: array([ 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28])