2009-12-11 28 views
14

El método astype() de matrices numpy no es muy eficiente. Tengo una matriz que contiene 3 millones de puntos Uint8. Multiplicarlo por una matriz de 3x3 toma 2 segundos, pero convertir el resultado de uint16 a uint8 toma otro segundo.numpy: Cómo convertir un tipo de matriz rápidamente

Más precisamente:

print time.clock() 
    imgarray = np.dot(imgarray, M)/255 
    print time.clock() 
    imgarray = imgarray.clip(0, 255) 
    print time.clock() 
    imgarray = imgarray.astype('B') 
    print time.clock() 

producto escalar y la escala se lleva a 2 seg
recorte toma 200 mseg conversión de tipo toma 1 sec

Dado el tiempo empleado por las otras operaciones, esperaría astype para ser mas rapido ¿Existe alguna manera más rápida de realizar la conversión de tipo, o estoy equivocado al estimar que la conversión de ese tipo no debería ser tan difícil?

Editar: el objetivo es salvar a la matriz final de 8 bits en un archivo

+0

¿Por qué necesita para ir a uint16 y viceversa? ¿Es posible tener 'M' como una matriz uint8, entonces no necesita la conversión. – u0b34a0f6ae

+0

el resultado del producto escalará el rango uint8. Originalmente estaba usando una matriz flotante M, y pensé que ir al número entero me daría alguna mejora, pero esto no es cierto. – shodanex

+0

Lo que toma todo ese tiempo, probablemente, es acceder a todas las ubicaciones de memoria. Suena difícil de arreglar –

Respuesta

24

Cuando se utiliza imgarray = imgarray.astype('B'), se obtiene una copia de la matriz, convertido al tipo especificado. Esto requiere una asignación de memoria adicional, aunque inmediatamente se voltea imgarray para apuntar a la matriz recién asignada.

Si utiliza imgarray.view('uint8'), a continuación, se obtiene una vista de la matriz. Utiliza los mismos datos, excepto que se interpreta como uint8 en lugar de imgarray.dtype. (np.dot devuelve una matriz uint32, por lo que después de la np.dot, imgarray es de tipo uint32.)

El problema con el uso view, sin embargo, es que un entero de 32 bits se convierte vista como 4 números enteros de 8 bits, y solo se preocupa por el valor en los últimos 8 bits. Entonces debemos saltarnos a cada 4º entero de 8 bits. Podemos hacer eso con rebanar:

imgarray.view('uint8')[:,::4]

comando% timeit de IPython muestra que hay una velocidad significativa a hacer las cosas de esta manera:

In [37]: %timeit imgarray2 = imgarray.astype('B') 
10000 loops, best of 3: 107 us per loop 

In [39]: %timeit imgarray3 = imgarray.view('B')[:,::4] 
100000 loops, best of 3: 3.64 us per loop 
+1

¿Puedo guardar esta vista en un archivo – shodanex

+0

@shodanex: Sí, podría usar np.save(). Consulte http://docs.scipy.org/doc/numpy-1.3.x/reference/generated/numpy.save.html – unutbu

+0

@shodanex: para otras opciones de formato, consulte también http://docs.scipy.org/doc /numpy-1.3.x/reference/routines.io.html – unutbu

Cuestiones relacionadas