ger*_*rit 13 python arrays indexing numpy
我刚刚发现 - 偶然 - 数组numpy可能被空元组索引:
In [62]: a = arange(5)
In [63]: a[()]
Out[63]: array([0, 1, 2, 3, 4])
Run Code Online (Sandbox Code Playgroud)
我在numpy wiki ZeroRankArray上找到了一些文档:
(Sasha)首先,无论对x [...]和x [()]做出什么选择,它们都应该是相同的,因为......对于"尽可能多的:必要的"只是语法糖,在零的情况下rank导致... =(:,)*0 =().其次,排名为零的数组和numpy标量类型在numpy内是可互换的,但numpy标量可以用在某些python结构中,其中ndarrays不能.
因此,对于0-d阵列a[()]和a[...]应该是等效的.它们也适用于高维阵列吗?他们强烈地看起来像是:
In [65]: a = arange(25).reshape(5, 5)
In [66]: a[()] is a[...]
Out[66]: False
In [67]: (a[()] == a[...]).all()
Out[67]: True
In [68]: a = arange(3**7).reshape((3,)*7)
In [69]: (a[()] == a[...]).all()
Out[69]: True
Run Code Online (Sandbox Code Playgroud)
但是,它不是语法糖.不适用于高维数组,甚至不适用于0维数组:
In [76]: a[()] is a
Out[76]: False
In [77]: a[...] is a
Out[77]: True
In [79]: b = array(0)
In [80]: b[()] is b
Out[80]: False
In [81]: b[...] is b
Out[81]: True
Run Code Online (Sandbox Code Playgroud)
然后有一个空列表索引的情况,它完全做了其他事情,但看起来相当于用空索引ndarray:
In [78]: a[[]]
Out[78]: array([], shape=(0, 3, 3, 3, 3, 3, 3), dtype=int64)
In [86]: a[arange(0)]
Out[86]: array([], shape=(0, 3, 3, 3, 3, 3, 3), dtype=int64)
In [82]: b[[]]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
IndexError: 0-d arrays can't be indexed.
Run Code Online (Sandbox Code Playgroud)
因此,它看起来()和...相似但不完全相同,索引与完全相同的[]东西.和a[]或者b[]是SyntaxError秒.在索引数组中记录了使用列表建立索引,并且在同一文档的末尾有关于使用元组进行索引的简短通知.
这留下了一个问题:
是a[()]和a[...]设计之间的区别?那么设计是什么?
(问题莫名其妙地想到:在Matlab矩阵上空的`()`做什么?)
编辑:
实际上,即使是标量也可能被空元组索引:
In [36]: numpy.int64(10)[()]
Out[36]: 10
Run Code Online (Sandbox Code Playgroud)
的治疗A[...]是一个特例,优化,总是返回A本身:
if (op == Py_Ellipsis) {
Py_INCREF(self);
return (PyObject *)self;
}
Run Code Online (Sandbox Code Playgroud)
还有什么,应该是相当于例如A[:],A[(Ellipsis,)],A[()],A[(slice(None),) * A.ndim]反而会返回一个视图的整体A,它base是A:
>>> A[()] is A
False
>>> A[()].base is A
True
Run Code Online (Sandbox Code Playgroud)
这似乎是不必要的和不成熟的优化,因为A[(Ellipsis,)]并且A[()]将始终给出相同的结果(整个视图A).从查看https://github.com/numpy/numpy/commit/fa547b80f7035da85f66f9cbabc4ff75969d23cd看起来它最初是必需的,因为索引...在0d数组上无法正常工作(之前为https://github.com/numpy/numpy)/commit/4156b241aa3670f923428d4e72577a9962cdf042它将元素作为标量返回,然后扩展到所有数组以保持一致性; 从那时起,索引已经在0d数组上得到修复,因此不需要进行优化,但它可以设置为残留(并且可能存在一些依赖于A[...] is A真实的代码).
虽然在您给出的示例中,空元组和省略号给出了类似的结果,但通常它们用于不同的目的。索引数组时,A[i, j, k] == A[(i, j, k)]特别是A[...] == A[(Ellipsis,)]. 这里元组只是作为索引元素的容器。当您需要将索引作为变量进行操作时,这会很有用,例如您可以执行以下操作:
index = (0,) * A.ndim
A[index]
Run Code Online (Sandbox Code Playgroud)
请注意,因为元组是索引元素的容器,所以它不能与其他索引组合,例如A[(), 0] == A[[], 0]and A[(), 0] != A[..., 0]。
因为A可以使用比 更少的索引来索引数组A.ndim,所以使用空元组进行索引是该行为的自然扩展,并且在某些情况下可能很有用,例如,上面的代码 snipit 将在 时工作A.ndim == 0。
简而言之,元组充当索引元素的容器,允许为空,而省略号是可能的索引元素之一。
根据Numpy 官方文档,差异很明显:
空(元组)索引是零维数组的完整标量索引。如果为零维,
x[()]则返回标量,否则返回视图。x另一方面x[...]总是返回一个视图。当存在省略号 (
...) 但没有大小(即替换零:)时,结果仍将始终是一个数组。如果不存在高级索引,则为视图,否则为副本。
>>> import numpy as np
>>> # ---------------------------------- #
>>> # when `x` is at least 1 dimensional #
>>> # ---------------------------------- #
>>> x = np.linspace(0, 10, 100)
>>> x.shape
(100,)
>>> x.ndim
1
>>> a = x[()]
>>> b = x[...]
>>> id(x), id(a), id(b)
(4559933568, 4561560080, 4585410192)
>>> id(x.base), id(a.base), id(b.base)
(4560914432, 4560914432, 4560914432)
>>> # ---------------------------- #
>>> # when `z` is zero dimensional #
>>> # ---------------------------- #
>>> z = np.array(3.14)
>>> z.shape
()
>>> z.ndim
0
>>> a = z[()]
>>> b = z[...]
>>> type(a), type(b)
(<class 'numpy.float64'>, <class 'numpy.ndarray'>)
>>> id(z), id(a), id(b)
(4585422896, 4586829384, 4561560080)
>>> id(z.base), id(a.base), id(b.base)
(4557260904, 4557260904, 4585422896)
>>> b.base is z
True
Run Code Online (Sandbox Code Playgroud)