Python中的"三个点"在索引看起来像数字时是什么意思?

Nan*_*Hua 56 python iterator numpy

x [...]下面是什么意思?

a = np.arange(6).reshape(2,3)
for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = 2 * x
Run Code Online (Sandbox Code Playgroud)

hpa*_*ulj 46

虽然建议重复Python Ellipsis对象做什么?在一般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]])
Run Code Online (Sandbox Code Playgroud)

请注意,我必须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
Run Code Online (Sandbox Code Playgroud)

但在这种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'> ()
...
Run Code Online (Sandbox Code Playgroud)

而且因为它是0d,x[:]所以不能代替使用x[...]

----> 3     x[:] = 2 * x
IndexError: too many indices for array
Run Code Online (Sandbox Code Playgroud)

更简单的数组迭代也可能提供洞察力:

In [675]: for x in a:
     ...:     print(x, x.shape)
     ...:     x[:] = 2 * x
     ...:     
[ 0  8 16] (3,)
[24 32 40] (3,)
Run Code Online (Sandbox Code Playgroud)

这会迭代行(第一个暗淡)a. x然后是一个1d数组,可以使用x[:]=...或修改x[...]=....

如果我添加了external_loop从下一个标志部分,x现在是一维数组,并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,)
Run Code Online (Sandbox Code Playgroud)

比较这个简单的行迭代(在2d数组上):

In [675]: for x in a:
     ...:     print(x, x.shape)
     ...:     x[:] = 2 * x
     ...:     
[ 0  8 16] (3,)
[24 32 40] (3,)
Run Code Online (Sandbox Code Playgroud)

这会迭代行(第一个暗淡)a. x然后是一个1d数组,可以使用x[:] = ...或修改x[...] = ....

阅读并试验此nditer页面一直到最后.它本身nditer并没有那么有用python.它不会加速迭代 - 直到你将代码移植到cython.np.ndindex是少数使用的非编译numpy函数之一nditer.


Aer*_*rin 6

省略号的...意思是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])
Run Code Online (Sandbox Code Playgroud)

这使得一次只操作一个维度变得容易。

一件事 - 在任何给定的索引表达式中您只能有一个省略号,否则您的表达式将不明确:每个应该放入多少个省略号。

  • 你写了“as much : as need”,但是在“Y[...,0]”中,*需要*多少个?我认为没有。“尽可能多:尽可能*”会更正确吗? (2认同)

Dor*_*iel 6

我相信一个很好的相似之处(大多数人可能已经习惯了)就是这样思考:

import numpy as np

random_array = np.random.rand(2, 2, 2, 2)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,[:, :, :, 0] and [..., 0]都是一样的。

您可以仅用于分析特定维度,假设您有一批 50 128x128 RGB 图像(50, 3, 128, 128),如果您想在每个颜色通道的每个图像中切片一部分,您可以做image[:,:,50:70, 20:80] or image[...,50:70,20:80]

请注意,您不能在类似于“无效”的语句中多次使用它[...,0,...]