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
.
省略号的...
意思是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)
这使得一次只操作一个维度变得容易。
一件事 - 在任何给定的索引表达式中您只能有一个省略号,否则您的表达式将不明确:
每个应该放入多少个省略号。
我相信一个很好的相似之处(大多数人可能已经习惯了)就是这样思考:
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,...]
。