2010-05-05 20 views
5

Tengo una función foo que toma una matriz NxM numpy como argumento y devuelve un valor escalar. Tengo una matriz AxNxM numpy data, sobre la que me gustaría mapa foo darme una matriz numpy resultante de la longitud A.Funciones de mapeo de matrices numpy 2D

Curently, estoy haciendo esto:

result = numpy.array([foo(x) for x in data]) 

Funciona, pero parece que no estoy aprovechando la magia numpy (y la velocidad). ¿Hay una mejor manera?

Miré numpy.vectorize, y numpy.apply_along_axis, pero ninguno funciona para una función de matrices 2D.

EDITAR: Estoy haciendo la regresión aumentada en parches de imagen 24x24, por lo que mi AxNxM es algo así como 1000x24x24. Lo que llamé foo de arriba aplica una característica similar a Haar a un parche (por lo tanto, no es terriblemente intensivo computacionalmente).

+1

Puede haber una manera de recodificar 'foo' para que pueda aceptar una matriz numpy de dimensión arbitraria, la aplicación de sus cálculos a los dos últimos ejes. Pero tendríamos que ver cómo 'foo' está codificado para hacer sugerencias específicas. – unutbu

+0

He agregado más detalles sobre mi problema específico. ¿Tendría sentido dejar 'data' como está, volver a codificar' foo' para tomar un parámetro de índice, y luego vectorizarlo y asignarlo sobre un 'arange (len (x))'? – perimosocordiae

Respuesta

3

Si NxM es grande (digamos, 100), el costo de iterar sobre A se amortizará básicamente en nada.

Di la matriz es 1000 X 100 X 100.

iteración es O (1000), pero el coste acumulativo de la función interior es O (1000 X 100 X 100) - 10.000 veces más lenta. (Nota, mi terminología es un poco flojo, pero sí sé lo que estoy hablando)

No estoy seguro, pero usted podría intentar esto:

result = numpy.empty(data.shape[0]) 
for i in range(len(data)): 
    result[i] = foo(data[i]) 

Se podría ahorrar una gran de asignación de memoria en la construcción de la lista ... pero la sobrecarga del ciclo sería mayor.

O podría escribir una versión paralela del bucle y dividirla en varios procesos. Eso podría ser mucho más rápido, dependiendo de qué tan intensivo sea foo (ya que tendría que compensar el manejo de datos).

+4

Variación: 'result = np.fromiter (itertools.imap (f, data), dtype = data.dtype, count = data.shape [0])' – jfs

1

Puede lograr eso remodelando su matriz 3D como una matriz 2D con la misma dimensión inicial, y ajuste su función foo con una función que funcione en matrices 1D al remodelarlas según lo requerido por foo. Un ejemplo (usando trace en lugar de foo):

from numpy import * 

def apply2d_along_first(func2d, arr3d): 
    a, n, m = arr3d.shape 
    def func1d(arr1d): 
     return func2d(arr1d.reshape((n,m))) 
    arr2d = arr3d.reshape((a,n*m)) 
    return apply_along_axis(func1d, -1, arr2d) 

A, N, M = 3, 4, 5 
data = arange(A*N*M).reshape((A,N,M)) 

print data 
print apply2d_along_first(trace, data) 

de salida:

[[[ 0 1 2 3 4] 
    [ 5 6 7 8 9] 
    [10 11 12 13 14] 
    [15 16 17 18 19]] 

[[20 21 22 23 24] 
    [25 26 27 28 29] 
    [30 31 32 33 34] 
    [35 36 37 38 39]] 

[[40 41 42 43 44] 
    [45 46 47 48 49] 
    [50 51 52 53 54] 
    [55 56 57 58 59]]] 
[ 36 116 196] 
+1

'np.fromiter (imap (' variante es 3-5 veces) más rápido que 'apply2d _ ..()' – jfs