Existe-t-il une fonction pour obtenir un itérateur sur une dimension arbitraire d'un tableau numpy?
Itérer sur la première dimension est facile ...
In [63]: c = numpy.arange(24).reshape(2,3,4)
In [64]: for r in c :
....: print r
....:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]
Mais itérer sur d'autres dimensions est plus difficile. Par exemple, la dernière dimension:
In [73]: for r in c.swapaxes(2,0).swapaxes(1,2) :
....: print r
....:
[[ 0 4 8]
[12 16 20]]
[[ 1 5 9]
[13 17 21]]
[[ 2 6 10]
[14 18 22]]
[[ 3 7 11]
[15 19 23]]
Je crée un générateur pour le faire moi-même, mais je suis surpris qu'il n'y ait pas de fonction nommée quelque chose comme numpy.ndarray.iterdim (axis = 0) pour le faire automatiquement.
Ce que vous proposez est assez rapide, mais la lisibilité peut être améliorée avec des formes plus claires:
for i in range(c.shape[-1]):
print c[:,:,i]
ou mieux (plus rapide, plus général et plus explicite):
for i in range(c.shape[-1]):
print c[...,i]
Cependant, la première approche ci-dessus semble être environ deux fois plus lente que l'approche swapaxes()
:
python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
'for r in c.swapaxes(2,0).swapaxes(1,2): u = r'
100000 loops, best of 3: 3.69 usec per loop
python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
'for i in range(c.shape[-1]): u = c[:,:,i]'
100000 loops, best of 3: 6.08 usec per loop
python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
'for r in numpy.rollaxis(c, 2): u = r'
100000 loops, best of 3: 6.46 usec per loop
Je suppose que cela est dû au fait que swapaxes()
ne copie aucune donnée, et parce que la gestion de c[:,:,i]
Peut être effectuée via du code général (qui gère le cas où :
Est remplacé par une tranche plus compliquée).
Notez cependant que la deuxième solution plus explicite c[...,i]
Est à la fois assez lisible et assez rapide:
python -m timeit -s 'import numpy; c = numpy.arange(24).reshape(2,3,4)' \
'for i in range(c.shape[-1]): u = c[...,i]'
100000 loops, best of 3: 4.74 usec per loop
J'utiliserais ce qui suit:
c = numpy.arange(2 * 3 * 4)
c.shape = (2, 3, 4)
for r in numpy.rollaxis(c, 2):
print(r)
La fonction rollaxis crée une nouvelle vue sur le tableau. Dans ce cas, il déplace l'axe 2 vers l'avant, équivalent à l'opération c.transpose(2, 0, 1)
.
Ainsi, on peut facilement parcourir la première dimension, comme vous l'avez montré. Une autre façon de le faire pour une dimension arbitraire consiste à utiliser numpy.rollaxis () pour amener la dimension donnée à la première (le comportement par défaut), puis à utiliser le tableau renvoyé (qui est une vue, donc c'est rapide) comme itérateur .
In [1]: array = numpy.arange(24).reshape(2,3,4)
In [2]: for array_slice in np.rollaxis(array, 1):
....: print array_slice.shape
....:
(2, 4)
(2, 4)
(2, 4)
EDIT: Je commenterai que j'ai soumis un PR à numpy pour adresser ceci ici: https://github.com/numpy/numpy/pull/3262 . Le consensus était que cela ne suffisait pas à ajouter à la base de code numpy. Je pense que l'utilisation de np.rollaxis est la meilleure façon de le faire, et si vous voulez un interateur, enveloppez-le dans iter ().
Je suppose qu'il n'y a pas de fonction. Lorsque j'ai écrit ma fonction, j'ai fini par prendre l'itération EOL également suggérée. Pour les futurs lecteurs, le voici:
def iterdim(a, axis=0) :
a = numpy.asarray(a);
leading_indices = (slice(None),)*axis
for i in xrange(a.shape[axis]) :
yield a[leading_indices+(i,)]
Vous pouvez utiliser numpy.shape pour obtenir les dimensions, puis varier pour les parcourir.
n0, n1, n2 = numpy.shape(c)
for r in range(n0):
print(c[r,:,:])