在文档中,它说(强调我的):
当选择对象obj为a时,将触发高级索引 非元组序列对象,ndarray(数据类型为integer或bool), 或者具有至少一个序列对象或ndarray(数据类型的元组)的元组 整数或布尔)。高级索引有两种类型:整数 和布尔。
<剪断>
同时认识到
x[[1,2,3]]
将触发高级索引,而则会触发x[[1,2,slice(None)]]
将触发基本切片。
我知道为什么x[(1, 2, slice(None))]
会触发基本切片。但是,当x[[1,2,slice(None)]]
满足作为非元组序列的条件时,为什么[1,2,slice(None)]
会触发基本切片?
在相关的说明中,为什么会发生以下情况?
>>> a = np.eye(4)
>>> a[(1, 2)] # basic indexing, as expected
0.0
>>> a[(1, np.array(2))] # basic indexing, as expected
0.0
>>> a[[1, 2]] # advanced indexing, as expected
array([[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.]])
>>> a[[1, np.array(2)]] # basic indexing!!??
0.0
答案 0 :(得分:8)
该规则有例外。高级索引文档部分没有提及它,但在上面Basic Slicing and Indexing部分的开头附近,您将看到以下文本:
为了保持与Numeric中常见用法的向后兼容,如果选择对象是包含切片对象的任何非ndarray序列(例如列表),则也会启动基本切片,省略号object或newaxis对象,但不适用于整数数组或其他嵌入式序列。
a[[1, np.array(2)]]
并未完全触发基本索引。它会触发向后兼容逻辑的未记录部分,如源代码中的comment中所述:
/*
* Sequences < NPY_MAXDIMS with any slice objects
* or newaxis, Ellipsis or other arrays or sequences
* embedded, are considered equivalent to an indexing
* tuple. (`a[[[1,2], [3,4]]] == a[[1,2], [3,4]]`)
*/
列表中的np.array(2)
会将列表视为元组,但结果a[(1, np.array(2))]
仍然是高级索引操作。与1
不同,它最终会将2
和a[[1, 2]]
应用于单独的轴,结果最终看起来与a[1, 2]
相同,但如果您尝试使用3D a
,它会生成副本而不是视图。
答案 1 :(得分:1)
使用虚拟课程,我可以确定口译员如何将[...]
翻译为__getitem__
的调用。
In [1073]: class Foo():
...: def __getitem__(idx):
...: print(idx)
In [1080]: Foo()[1,2,slice(None)]
(1, 2, slice(None, None, None))
In [1081]: Foo()[(1,2,slice(None))]
(1, 2, slice(None, None, None))
In [1082]: Foo()[[1,2,slice(None)]]
[1, 2, slice(None, None, None)]
因此用()包装多个术语没有区别 - 它在两种情况下都会得到一个元组。列表作为列表传递。
因此元组和列表之间的区别(或不是)必须在numpy
源代码中编码 - 这是编译的。所以我不能轻易研究它。
使用1d数组
使用列表建立索引会生成高级索引 - 选择特定值:
In [1085]: arr[[1,2,3]]
Out[1085]: array([ 0.73703368, 0. , 0. ])
但是用元组或切片替换其中一个值:
In [1086]: arr[[1,2,(2,3)]]
IndexError: too many indices for array
In [1088]: arr[[1,2,slice(None)]]
IndexError: too many indices for array
并将列表视为元组 - 它会尝试将值与维度匹配。
因此,在顶层,列表和元组的处理方式相同 - 如果列表不能解释为高级索引列表。
另请注意单项列出
的区别In [1089]: arr[[1]]
Out[1089]: array([ 0.73703368])
In [1090]: arr[(1,)]
Out[1090]: 0.73703367969998546
In [1091]: arr[1]
Out[1091]: 0.73703367969998546
像np.apply_along/over_axis
这样的函数生成索引作为列表或数组,然后应用它。它们使用列表或数组,因为它是可变的。有些人在用作索引之前将其包装在tuple
中;别人没有打扰。这种差异让我感到困扰,但是这些测试用例表明这种经常包装的元组是可选的。
In [1092]: idx=[1,2,slice(None)]
In [1093]: np.ones((2,3,4))[idx]
Out[1093]: array([ 1., 1., 1., 1.])
In [1094]: np.ones((2,3,4))[tuple(idx)]
Out[1094]: array([ 1., 1., 1., 1.])
如果我将索引构建为对象数组,看起来仍然需要元组包装器:
In [1096]: np.ones((2,3,4))[np.array(idx)]
...
IndexError: arrays used as indices must be of integer (or boolean) type
In [1097]: np.ones((2,3,4))[tuple(np.array(idx))]
Out[1097]: array([ 1., 1., 1., 1.])
===================
来自函数@Eric
链接
/*
* Sequences < NPY_MAXDIMS with any slice objects
* or newaxis, Ellipsis or other arrays or sequences
* embedded, are considered equivalent to an indexing
* tuple. (`a[[[1,2], [3,4]]] == a[[1,2], [3,4]]`)
*/
===================
此函数将对象数组和列表包装在元组中以进行索引:
def apply_along_axis(func1d, axis, arr, *args, **kwargs):
....
ind = [0]*(nd-1)
i = zeros(nd, 'O')
....
res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
outarr[tuple(ind)] = res