14

我刚刚偶然发现一个数组 innumpy可能被一个空元组索引:

In [62]: a = arange(5)

In [63]: a[()]
Out[63]: array([0, 1, 2, 3, 4])

我在numpy wiki ZeroRankArray上找到了一些文档:

(萨沙)首先,无论对 x[...] 和 x[()] 做出何种选择,它们都应该是相同的,因为 ... 只是“尽可能多:必要时”的语法糖,在零的情况下排名导致 ... = (:,)*0 = ()。其次,零级数组和 numpy 标量类型在 numpy 中是可以互换的,但是 numpy 标量可以在 ndarrays 不能的某些 python 结构中使用。

因此,对于 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

但是,它不是语法糖。不适用于高维数组,甚至不适用于 0-d 数组:

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

然后是空列表索引的情况,它完全做其他事情,但看起来等同于使用空索引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.

因此,看起来()...相似但并不完全相同,并且索引[]完全意味着其他东西。And a[]or b[]are SyntaxErrors。使用列表进行索引记录在索引数组中,并且有一个关于使用元组索引的简短通知中,并且在同一文档的末尾

这就留下了一个问题:

a[()]和之间的区别是a[...]设计那么设计是什么?

(问题让人想起:空的`()`在Matlab矩阵上做了什么?

编辑:

事实上,即使是标量也可能被一个空元组索引:

In [36]: numpy.int64(10)[()]
Out[36]: 10
4

3 回答 3

8

的处理A[...]是一种特殊情况,经过优化以始终返回A自身

if (op == Py_Ellipsis) {
    Py_INCREF(self);
    return (PyObject *)self;
}

任何其他应该等价的东西,例如A[:], A[(Ellipsis,)], A[()],A[(slice(None),) * A.ndim]都将返回一个整体的视图A,其baseA

>>> A[()] is A
False
>>> A[()].base is A
True

这似乎是一种不必要且过早的优化,因为A[(Ellipsis,)]并且A[()]总是会给出相同的结果(关于 的完整视图A)。从查看https://github.com/numpy/numpy/commit/fa547b80f7035da85f66f9cbabc4ff75969d23cd看来,它最初是必需的,因为索引 with...在 0d 数组上无法正常工作(之前为https://github.com/numpy/numpy /commit/4156b241aa3670f923428d4e72577a9962cdf042它将元素作为标量返回),然后扩展到所有数组以保持一致性;从那时起,索引已固定在 0d 数组上,因此不需要优化,但它设法保留下来(并且可能有一些代码取决于A[...] is A真实情况)。

于 2013-02-04T18:12:21.877 回答
5

虽然在您给出的示例中,空元组和省略号给出了类似的结果,但通常它们用于不同的目的。索引数组时,A[i, j, k] == A[(i, j, k)]特别是A[...] == A[(Ellipsis,)]. 在这里,元组只是用作索引元素的容器。当您需要将索引作为变量进行操作时,这可能很有用,例如,您可以执行以下操作:

index = (0,) * A.ndim
A[index]

请注意,因为元组是索引元素的容器,所以它不能与其他索引组合,例如A[(), 0] == A[[], 0]A[(), 0] != A[..., 0]

A因为可以使用比 更少的索引来索引数组,所以A.ndim使用空元组进行索引是该行为的自然扩展,并且在某些情况下可能很有用,例如,上面的代码片段可以在A.ndim == 0.

简而言之,元组作为索引元素的容器,允许为空,而省略号是可能的索引元素之一。

于 2013-02-04T17:38:46.477 回答
5

根据官方 Numpy 文档,区别很明显:

空(元组)索引是零维数组的完整标量索引。如果是零维x[()]则返回标量,否则返回视图。x另一方面,x[...]总是返回一个 view

当省略号 ( ...) 存在但没有大小(即替换零 :)时,结果仍将始终是一个数组。如果不存在高级索引,则为视图,否则为副本。

>>> 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
于 2018-10-24T03:19:23.453 回答