Хотя предлагаемый дубликат Что делает объект Python Ellipsis? отвечает на вопрос в общем pythonконтексте, его использование в nditerцикле требует, я думаю, дополнительной информации.
Регулярное присвоение в 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
...:
[ 0816] (3,)
[243240] (3,)
это итерация по строкам (1-й размер) a. xтогда является 1d-массивом и может быть изменен с помощью x[:]=...или x[...]=....
И если я добавлю 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
[ 01632486480] <class 'numpy.ndarray'> (6,)
Сравните эту простую итерацию строки (в двумерном массиве):
In [675]: for x in a:
...: print(x, x.shape)
...: x[:] = 2 * x
...:
[ 0816] (3,)
[243240] (3,)
это итерация по строкам (1-й размер) a. xтогда является 1d-массивом и может быть изменен с помощью x[:] = ...или x[...] = ....
Прочтите и поэкспериментируйте с этой nditerстраницей до конца. Сам по себе nditerне так уж и полезен python. Это не ускоряет итерацию - пока вы не перенесете свой код в cython. np.ndindex- одна из немногих нескомпилированных numpyфункций, использующих nditer.
Ответы:
Хотя предлагаемый дубликат Что делает объект Python Ellipsis? отвечает на вопрос в общем
python
контексте, его использование вnditer
цикле требует, я думаю, дополнительной информации.https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#modifying-array-values
Этот раздел включает ваш пример кода.
Так что, по моим словам,
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,)
это итерация по строкам (1-й размер)
a
.x
тогда является 1d-массивом и может быть изменен с помощьюx[:]=...
илиx[...]=...
.И если я добавлю
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,)
Сравните эту простую итерацию строки (в двумерном массиве):
In [675]: for x in a: ...: print(x, x.shape) ...: x[:] = 2 * x ...: [ 0 8 16] (3,) [24 32 40] (3,)
это итерация по строкам (1-й размер)
a
.x
тогда является 1d-массивом и может быть изменен с помощьюx[:] = ...
илиx[...] = ...
.Прочтите и поэкспериментируйте с этой
nditer
страницей до конца. Сам по себеnditer
не так уж и полезенpython
. Это не ускоряет итерацию - пока вы не перенесете свой код вcython
.np.ndindex
- одна из немногих нескомпилированныхnumpy
функций, использующихnditer
.источник