2012-09-30 16 views
10

Estoy tratando de entender cómo trabajar con nditer para hacer una reducción de , en mi caso, convertir una matriz de 3d en una matriz de 2d.Cómo hacer una reducción con numpy.nditer en el primer eje

que siguieron la ayuda aquí http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html y logrado crear una función que se aplica la reducción en el último eje de la entrada. Con esta función

def nditer_sum(data, red_axes): 
    it = numpy.nditer([data, None], 
      flags=['reduce_ok', 'external_loop'], 
      op_flags=[['readonly'], ['readwrite', 'allocate']], 
      op_axes=[None, red_axes]) 
    it.operands[1][...] = 0 

    for x, y in it: 
     y[...] = x.sum() 

    return it.operands[1] 

puedo conseguir algo equivalente a data.sum (eje Y = 2)

>>> data = numpy.arange(2*3*4).reshape((2,3,4)) 
>>> nditer_sum(data, [0, 1, -1]) 
[[ 6 22 38] 
[54 70 86]] 
>>> data.sum(axis=2) 
[[ 6 22 38] 
[54 70 86]] 

Así que para conseguir algo equivalente a data.sum (eje = 0) que a pesar de que fue suficiente para cambiar el argumento red_axes a [-1, 0,1] Pero el resultado es bastante diferente.

>>> data = numpy.arange(2*3*4).reshape((2,3,4)) 
>>> data.sum(axis=0) 
[[12 14 16 18] 
[20 22 24 26] 
[28 30 32 34]] 
>>> nditer_sum(data, [-1, 0, 1]) 
[[210 210 210 210] 
[210 210 210 210] 
[210 210 210 210]] 

En el bucle interior nditer_sum (para x, y en ella :), el iterador es bucle 2 veces y dando una matriz de longitud 12 cada vez, en lugar de bucle 12 veces y dando una matriz de longitud 2 cada vez. Tengo leí la documentación numpy varias veces y busqué en Google al en vano. Estoy usando numpy 1.6 y python 2.7

+0

-1 en op_axes se documenta como "nuevo eje", es esto lo que está intentando ¿que hacer? También la documentación introduce [[tamaño x], [tamaño y], [tamaño z]] en op_axes, mientras presiona [Ninguno, [tamaño 3]], ¿está previsto? –

+0

La [documentación] (http://docs.scipy.org/doc/numpy/reference/generated/numpy.nditer.html) dice "un operando es un mapeo desde las dimensiones del iterador a las dimensiones del operando" ... Lo que sea que eso signifique. En el ejemplo actual, he copiado el código en el [iterating over arrays tutorial] (http://docs.scipy.org/doc/numpy-dev/reference/arrays.nditer.html#reduction-iteration), que funciona, pero solo con el ultimo eje En el ejemplo, la matriz 3d tiene Op_axes None (que parece equivalente a [-1, -1, -1]) y el eje 2d tiene [0, 1, -1] – Sergio

+0

Creo que cambiando [0,1, - 1] a [-1, 0, 1] haría la reducción en el primer eje, pero no funciona.Mi pregunta es cómo hacer la reducción en un eje arbitrario. – Sergio

Respuesta

0

Al cambiar la línea y[...] = x.sum() a y[...] += x se corrige (como en el ejemplo here).

+0

Pero eso no es lo que quiero hacer. Estoy usando una función más compleja que realiza un montón de operaciones en x. Imagina que en lugar de la suma es "la suma después de recortar el 10% menor que x" – Sergio

+0

Solo digo que la corrección hace que el comportamiento sea consistente con numpy.sum con cualquier eje especificado, lo que parecía ser la pregunta. .. Tal vez deberías agregar detalles a la pregunta. – Benjamin

1

La caja axis=0 funciona correctamente si la orden nditer se cambia a F. Ahora hay 12 pasos con matrices de tamaño (2), como quisiera.

it = np.nditer([data, None], 
     flags=['reduce_ok', 'external_loop'], 
     op_flags=[['readonly'], ['readwrite', 'allocate']], 
     order='F',  # ADDED to loop starting with the last dimension 
     op_axes=[None, red_axes]) 

Pero no hay una solución como esta para la caja del medio axis=1.


Otro enfoque para iterando dimensiones seleccionadas es construir un iterador 'multi_index' en una matriz dimensional reducida. Descubrí en https://stackoverflow.com/a/25097271/901925 que np.ndindex usa este truco para realizar una "iteración superficial".

Para el caso axis=0, esta función funciona:

def sum_1st(data): 
    y = np.zeros(data.shape[1:], data.dtype) 
    it = np.nditer(y, flags=['multi_index']) 
    while not it.finished: 
     xindex = tuple([slice(None)]+list(it.multi_index)) 
     y[it.multi_index] = data[xindex].sum() 
     it.iternext() 
    return y 

o generalizado a cualquier eje:

def sum_any(data, axis=0): 
    yshape = list(data.shape) 
    del yshape[axis] 
    y = np.zeros(yshape, data.dtype) 
    it = np.nditer(y, flags=['multi_index']) 
    while not it.finished: 
     xindex = list(it.multi_index) 
     xindex.insert(axis, slice(None)) 
     y[it.multi_index] = data[xindex].sum() 
     it.iternext() 
    return y 
Cuestiones relacionadas