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
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 duplicata proposé Que fait l'objet Python Ellipsis ? répond à la question de manière générale python
contexte, son utilisation dans un nditer
boucle nécessite, je pense, des informations supplémentaires.
https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#modifying-array-values
L'affectation régulière en Python change simplement une référence dans le dictionnaire des variables locales ou globales au lieu de modifier une variable existante sur place. Cela signifie que la simple affectation à x ne placera pas la valeur dans l'élément du tableau, mais fera plutôt passer x d'une référence à un élément du tableau à une référence à la valeur que vous avez affectée. Pour modifier réellement l'élément du tableau, x doit être indexé avec le point de suspension.
Cette section comprend votre exemple de code.
Donc, selon mes mots, le x[...] = ...
modifie x
en place ; x = ...
aurait rompu le lien avec le nditer
et ne l'a pas modifiée. C'est comme si x[:] = ...
mais fonctionne avec des tableaux de toute dimension (y compris 0d). Dans ce contexte x
n'est pas seulement un nombre, c'est un tableau.
Peut-être que la chose la plus proche de cette nditer
itération, 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]])
Remarquez que j'ai dû indexer et modifier a[i]
directement. Je n'aurais pas pu l'utiliser, x = 2*x
. Dans cette itération x
est un scalaire, et donc non mutable
In [669]: for i,x in np.ndenumerate(a):
...: x[...] = 2 * x
...
TypeError: 'numpy.int32' object does not support item assignment
Mais dans le nditer
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 parce que c'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,)
ceci itère sur les rangées (1ère dim) de a
. x
est alors un tableau 1d, et peut être modifié avec soit x[:]=...
ou x[...]=...
.
Et si j'ajoute le 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é tous les autres nditer
exemples.
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 en 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,)
ceci itère sur les rangées (1ère dim) de a
. x
est alors un tableau 1d, et peut être modifié avec soit x[:] = ...
ou x[...] = ...
.
Lisez et expérimentez avec ceci nditer
page jusqu'à la fin. Par lui-même, nditer
n'est pas très utile dans python
. Il n'accélère pas l'itération - pas jusqu'à ce que vous portiez votre code vers cython
. np.ndindex
est l'un des rares programmes non compilés numpy
qui utilise nditer
.
L'ellipse ...
signifie as many : as needed
.
Pour les personnes qui n'ont pas le temps, voici un exemple simple :
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])
Cela permet de manipuler facilement une seule dimension à la fois.
Une chose - Vous ne pouvez avoir qu'une seule ellipse dans une expression d'indexation donnée, ou votre expression serait ambiguë quant au nombre d'ellipses. :
devrait être mis dans chacun.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
1 votes
Ce n'est pas une liste.
2 votes
Duplicata possible de Que fait l'objet Python Ellipsis ?
1 votes
La conférence de James Powell est une façon amusante de comprendre cela. youtube.com/watch?v=65_-6kEAq58