2009-10-19 10 views
34

¿Hay alguna función para obtener un iterador sobre una dimensión arbitraria de una matriz numpy?Iteración sobre la dimensión arbitraria de numpy.array

iteración en la primera dimensión es fácil ...

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]] 

Pero iteración en otras dimensiones es más difícil. Por ejemplo, la última dimensión:

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]] 

estoy haciendo un generador de hacer esto por mí mismo, pero me sorprende que no hay una función llamada algo así como numpy.ndarray.iterdim (eje = 0) a haz esto automáticamente

Respuesta

36

Lo que proponemos es bastante rápido, pero la legibilidad se puede mejorar con las formas más claras:

for i in range(c.shape[-1]): 
    print c[:,:,i] 

o, mejor (más rápido, más general y más explícito):

for i in range(c.shape[-1]): 
    print c[...,i] 

Sin embargo , el primer enfoque anterior parece ser aproximadamente el doble de lento que el enfoque 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 

Supongo que esto se debe a que swapaxes() no copia ningún dato, y porque el manejo de c[:,:,i] se puede hacer a través del código general (que maneja el caso donde : se reemplaza por un segmento más complicado).

Nota sin embargo que la segunda solución más explícito c[...,i] es a la vez muy legibles y bastante rápido:

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 
3

supongo que no hay ninguna función. Cuando escribí mi función, terminé tomando la iteración que EOL también sugirió. Para los futuros lectores, aquí está:

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,)] 
+0

La sintaxis NumPy estándar 'a [..., i]' sería más ligera y eliminaría la necesidad de 'leading_indices'. – EOL

+1

@EOL pero eso funcionaría solo para el último eje, con leading_indices es más general ... – lukas

+0

Buen punto @lukas: la pregunta inicial de hecho menciona la iteración "sobre una dimensión arbitraria", mientras que yo tenía en mente la integración sobre la última dimensión. – EOL

14

que haría uso de lo siguiente:

c = numpy.arange(2 * 3 * 4) 
c.shape = (2, 3, 4) 

for r in numpy.rollaxis(c, 2): 
    print(r) 

La función rollaxis crea una nueva vista en la matriz. En este caso, está moviendo el eje 2 hacia adelante, equivalente a la operación c.transpose(2, 0, 1).

+1

+1: Muy directo, pero desafortunadamente un poco más lento que el simple enfoque 'c [:,:, i]' (no estoy seguro por qué). – EOL

4

Entonces, uno puede repetir la primera dimensión fácilmente, como lo ha demostrado. Otra forma de hacer esto para una dimensión arbitraria es usar numpy.rollaxis() para traer la dimensión dada al primero (el comportamiento predeterminado), y luego usar la matriz devuelta (que es una vista, así que esto es rápido) como un iterador .

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: Voy a comentar que presenté un PR a numpy para abordar esta aquí: https://github.com/numpy/numpy/pull/3262. El consenso era que esto no era suficiente para agregar a la base de código numpy. Creo que usar np.rollaxis es la mejor manera de hacerlo, y si quieres un interador, envuélvelo en iter().

Cuestiones relacionadas