下面的x [...]是什么意思?
a = np.arange(6).reshape(2,3)
for x in np.nditer(a, op_flags=['readwrite']):
x[...] = 2 * x
答案 0 :(得分:39)
虽然建议的重复What does the Python Ellipsis object do?在一般python
上下文中回答了问题,但我认为它在nditer
循环中的使用需要添加信息。
https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#modifying-array-values
Python中的常规赋值只是更改本地或全局变量字典中的引用,而不是修改现有变量。这意味着简单地分配给x不会将值放入数组的元素中,而是将x作为数组元素引用切换为对指定值的引用。要实际修改数组的元素,x应该用省略号索引。
该部分包含您的代码示例。
所以在我看来,x[...] = ...
就地修改了x
; x = ...
会破坏nditer
变量的链接,而不会更改它。它与x[:] = ...
类似,但适用于任何维度的数组(包括0d)。在这种情况下,x
不仅仅是一个数字,它还是一个数组。
在没有nditer
的情况下,与此nditer
次迭代最接近的可能是:
In [667]: for i, x in np.ndenumerate(a):
...: print(i, x)
...: a[i] = 2 * x
...:
(0, 0) 0
(0, 1) 1
...
(1, 2) 5
In [668]: a
Out[668]:
array([[ 0, 2, 4],
[ 6, 8, 10]])
请注意,我必须直接索引和修改a[i]
。我无法使用x = 2*x
。在此迭代中,x
是标量,因此不可变
In [669]: for i,x in np.ndenumerate(a):
...: x[...] = 2 * x
...
TypeError: 'numpy.int32' object does not support item assignment
但在nditer
情况下x
是一个0d数组,并且是可变的。
In [671]: for x in np.nditer(a, op_flags=['readwrite']):
...: print(x, type(x), x.shape)
...: x[...] = 2 * x
...:
0 <class 'numpy.ndarray'> ()
4 <class 'numpy.ndarray'> ()
...
由于它是0d,因此无法使用x[:]
代替x[...]
----> 3 x[:] = 2 * x
IndexError: too many indices for array
更简单的数组迭代也可能提供洞察力:
In [675]: for x in a:
...: print(x, x.shape)
...: x[:] = 2 * x
...:
[ 0 8 16] (3,)
[24 32 40] (3,)
这会迭代a
的行(第一个暗淡)。 x
是一个1d数组,可以使用x[:]=...
或x[...]=...
进行修改。
如果我从下一个section添加external_loop
标记,则x
现在是1d数组,x[:] =
将起作用。但x[...] =
仍然有效,而且更为一般。所有其他x[...]
示例都使用了nditer
。
In [677]: for x in np.nditer(a, op_flags=['readwrite'], flags=['external_loop']):
...: print(x, type(x), x.shape)
...: x[...] = 2 * x
[ 0 16 32 48 64 80] <class 'numpy.ndarray'> (6,)
比较这个简单的行迭代(在2d数组上):
In [675]: for x in a:
...: print(x, x.shape)
...: x[:] = 2 * x
...:
[ 0 8 16] (3,)
[24 32 40] (3,)
这会迭代a
的行(第一个暗淡)。 x
是一个1d数组,可以使用x[:] = ...
或x[...] = ...
进行修改。
阅读并试用此nditer
页面一直到最后。 nditer
本身在python
中没有用处。它不会加速迭代 - 直到您将代码移植到cython
。np.ndindex
是少数使用numpy
的非编译nditer
函数之一。
答案 1 :(得分:1)
省略号 ...
表示 as many : as needed
。
对于没有时间的人,这里有一个简单的例子:
In [64]: X = np.reshape(np.arange(9), (3,3))
In [67]: Y = np.reshape(np.arange(2*3*4), (2,3,4))
In [70]: X
Out[70]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [71]: X[:,0]
Out[71]: array([0, 3, 6])
In [72]: X[...,0]
Out[72]: array([0, 3, 6])
In [73]: Y
Out[73]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
In [74]: Y[:,0]
Out[74]:
array([[ 0, 1, 2, 3],
[12, 13, 14, 15]])
In [75]: Y[...,0]
Out[75]:
array([[ 0, 4, 8],
[12, 16, 20]])
In [76]: X[0,...,0]
Out[76]: array(0)
In [77]: Y[0,...,0]
Out[77]: array([0, 4, 8])
这使得一次只操作一个维度变得容易。
有一点 - 在任何给定的索引表达式中您只能有一个省略号,否则您的表达式对于每个应该放入多少个 :
会产生歧义。