Quelle est la signification de x [...] ci-dessous?
a = np.arange(6).reshape(2,3)
for x in np.nditer(a, op_flags=['readwrite']):
x[...] = 2 * x
Alors que le doublon proposé Que fait l'objet Python Ellipsis? répond à la question dans un contexte général python
, son utilisation dans une boucle nditer
nécessite, je pense, des informations supplémentaires.
https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#modifying-array-values
Une affectation régulière dans Python change simplement une référence dans le dictionnaire de variables local ou global au lieu de modifier une variable existante à la place. Cela signifie que la simple affectation à x ne placera pas la valeur dans l'élément du tableau, mais fera en sorte que x ne soit plus une référence d'élément de tableau mais une référence à la valeur que vous avez attribuée. Pour réellement modifier l’élément du tableau, x doit être indexé avec l’Ellipsis.
Cette section comprend votre exemple de code.
Donc, dans mes mots, le x[...] = ...
modifie x
sur place; x = ...
aurait cassé le lien vers la variable nditer
sans le changer. C'est comme x[:] = ...
mais ça fonctionne avec des tableaux de n'importe quelle dimension (y compris 0d). Dans ce contexte, x
n'est pas simplement un nombre, c'est un tableau.
Peut-être que la chose la plus proche de cette itération nditer
, sans nditer
, est:
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]])
Notez que je devais indexer et modifier a[i]
directement. Je n'aurais pas pu utiliser, x = 2*x
. Dans cette itération, x
est un scalaire, et ne peut donc pas être modifié
In [669]: for i,x in np.ndenumerate(a):
...: x[...] = 2 * x
...
TypeError: 'numpy.int32' object does not support item assignment
Mais dans le cas nditer
, le cas x
est un tableau 0d, et mutable.
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'> ()
...
Et comme il est 0d, x[:]
ne peut pas être utilisé à la place de x[...]
----> 3 x[:] = 2 * x
IndexError: too many indices for array
Une itération de tableau plus simple pourrait également donner un aperçu:
In [675]: for x in a:
...: print(x, x.shape)
...: x[:] = 2 * x
...:
[ 0 8 16] (3,)
[24 32 40] (3,)
cela itère sur les lignes (1ère dim) de a
. x
est alors un tableau 1d et peut être modifié avec x[:]=...
ou x[...]=...
.
Et si j'ajoute le drapeau external_loop
du prochain section , x
est maintenant un tableau 1d et x[:] =
fonctionnerait. Mais x[...] =
fonctionne toujours et est plus général. x[...]
est utilisé par tous les autres exemples 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,)
Comparez cette simple itération de ligne (sur un tableau 2d):
In [675]: for x in a:
...: print(x, x.shape)
...: x[:] = 2 * x
...:
[ 0 8 16] (3,)
[24 32 40] (3,)
cela itère sur les lignes (1ère dim) de a
. x
est alors un tableau 1d et peut être modifié avec x[:] = ...
ou x[...] = ...
.
Lisez et testez cette page nditer
jusqu’à la fin. En soi, nditer
n'est pas très utile dans python
. Cela n'accélère pas l'itération - vous ne portez pas votre code dans cython
.np.ndindex
est l'une des rares fonctions numpy
non compilées qui utilise nditer
.