2011-04-22 16 views
16

¿Hay algo que pueda hacer para acelerar las matrices enmascaradas en numpy? Tenía una función terriblemente ineficiente que volví a escribir para utilizar matrices enmascaradas (donde podía simplemente enmascarar filas en lugar de hacer copias y eliminar filas como lo hacía). Sin embargo, me sorprendí al descubrir que la función enmascarada era 10 veces más lenta porque las matrices enmascaradas son mucho más lentas.Python/Numpy - Las matrices enmascaradas son muy lentas

Como ejemplo, tome las siguientes (enmascarado es más de 6 veces más lento para mí):

import timeit 
import numpy as np 
import numpy.ma as ma 

def test(row): 
    return row[0] + row[1] 

a = np.arange(1000).reshape(500, 2) 
t = timeit.Timer('np.apply_along_axis(test, 1, a)','from __main__ import test, a, np') 
print round(t.timeit(100), 6) 

b = ma.array(a) 
t = timeit.Timer('ma.apply_along_axis(test, 1, b)','from __main__ import test, b, ma') 
print round(t.timeit(100), 6) 
+2

Tenga en cuenta que las MaskedArrays son más convenientes que una solución real. Si necesita realizar cálculos intensivos en matrices de matrices con valores faltantes o indefinidos, en la mayoría de los casos, es mejor tratar con la máscara y los datos usted mismo. Hasta que se mejore la implementación de los valores faltantes o indefinidos en el código de NumPy (lo que debería suceder pronto), usted quedará atrapado en MaskedArrays. Sí, son bastante lentos, porque están codificados en Python puro, lo que por supuesto no puede ser tan eficiente como confiar en algún código C. –

+0

Gracias por la pregunta, esto confirma lo que sospechaba de mi código –

Respuesta

3

no tengo ni idea de por qué las funciones de matriz enmascarados se mueven tan lentamente, pero como parece que usted están usando la máscara para seleccionar filas (en contraposición a los valores individuales), se puede crear una matriz regular de las filas enmascarados y utilizar la función np lugar:

b.mask = np.zeros(500) 
b.mask[498] = True 
t = timeit.Timer('c=b.view(np.ndarray)[~b.mask[:,0]]; np.apply_along_axis(test, 1, c)','from __main__ import test, b, ma, np') 
print round(t.timeit(100), 6) 

Mejor aún, no utilice matrices enmascarados en absoluto ; simplemente mantenga sus datos y una matriz de máscara 1D como variables separadas:

a = np.arange(1000).reshape(500, 2) 
mask = np.ones(a.shape[0], dtype=bool) 
mask[498] = False 
out = np.apply_along_axis(test, 1, a[mask]) 
+0

terminé haciendo algo similar a su segundo ejemplo, pero necesitaba la variable 'salir' para tener la misma cantidad de índices que filas en un'. Ver [esta pregunta] (http://stackoverflow.com/questions/5761642/python-numpy-get-index-into-main-array-from-subset) –

0

EDIT: estaba probando mal mediante el uso de np.apply_along_axis en lugar de np.ma.apply_along_axis, lo siento. Así que confirman que la versión de serie enmascarado es más de 5 veces más lento también en Linux/numpy 1.5.1

In [16]: %timeit np.apply_along_axis(test, 1, a) 
100 loops, best of 3: 15.3 ms per loop 

In [17]: %timeit np.apply_along_axis(test, 1, b) 
100 loops, best of 3: 15.3 ms per loop 

In [12]: %timeit np.ma.apply_along_axis(test, 1, b) 
10 loops, best of 3: 80.8 ms per loop 

In [18]: np.__version__ 
Out[18]: '1.5.1' 
+0

Estoy usando python 2.5.2 y numpy 1.5.1 en Windows XP 32bit. Lo intentaré en mi computadora linux cuando llegue a casa. Muy raro. Como referencia, cuando ejecuto mi código publicado obtengo como salida: 0.955434 y 5.136362. –

+0

Estoy viendo una diferencia de rendimiento significativa también: 1.298489 para la primera, 7.177839 para la segunda. Estoy usando Python 2.6.4 y Numpy 1.5.1 en Linux 64 bits. – tkerwin

+0

En realidad, no veo la diferencia usando el comando '% timeit' como lo hizo en su ejemplo, pero lo hago cuando uso el' timeit.Timer'. Tal vez no entiendo cómo funciona uno de ellos. – tkerwin

Cuestiones relacionadas