2011-07-21 19 views
174

Lo creas o no, después de crear un perfil de mi código actual, la operación repetitiva de numpy array reversión comió una gran parte del tiempo de ejecución. Lo que tengo en este momento es el método basado en la opinión común:La manera más eficiente de invertir una matriz numpy

reversed_arr = arr[::-1] 

¿Hay alguna otra manera de hacerlo más eficiente, o es sólo una ilusión de mi obsesión con el rendimiento numpy poco realista?

+10

Er ... 'arr [:: - 1]' sólo devuelve una vista invertida. Es lo más rápido que puede obtener, y no depende de la cantidad de elementos en la matriz, ya que simplemente cambia los pasos. ¿Es lo que estás invirtiendo en realidad una matriz numpy? –

+0

sí, de hecho, 'arr' es una matriz numpy. – nye17

+10

Hmmm ... Bueno, en mi computadora portátil tarda unos 670 nanosegundos, independientemente de la longitud de la matriz. Si ese es su cuello de botella, es posible que tenga que cambiar de idioma ... Estoy bastante seguro de que no encontrará una forma más rápida de invertir una matriz numpy. ¡Buena suerte, en cualquier caso! –

Respuesta

148

Cuando crea reversed_arr está creando una vista en la matriz original. Luego puede cambiar la matriz original y la vista se actualizará para reflejar los cambios.

¿Está volviendo a crear la vista más a menudo de lo que necesita? Usted debe ser capaz de hacer algo como esto:

arr = np.array(some_sequence) 
reversed_arr = arr[::-1] 

do_something(arr) 
look_at(reversed_arr) 
do_something_else(arr) 
look_at(reversed_arr) 

No soy un experto numpy, pero esto parece que sería la forma más rápida de hacer las cosas de numpy. Si esto es lo que ya estás haciendo, no creo que puedas mejorarlo.

P.S. Gran discusión de puntos de vista numpy aquí:

View onto a numpy array?

+0

¿Ayuda crear un objeto de corte y luego reutilizarlo en muchas matrices? – endolith

+1

En realidad acabo de probarlo y no veo ninguna diferencia con el objeto de corte creado fuera del ciclo. (Oh, espera, es un poco más rápido. Repetidamente 43.4 ms vs 44.3 ms para un bucle de 1000000) – endolith

29

np.fliplr() voltea la matriz de izquierda a derecha.

Tenga en cuenta que para las matrices 1d, es necesario engañar un poco:

arr1d = np.array(some_sequence) 
reversed_arr = np.fliplr([arr1d])[0] 
+23

'reversed_arr = np.flipud (arr1d)' parece funcionar directamente. –

+0

@ThomasArildsen - interesante. Gracias – KolaB

3

voy a ampliar en la respuesta anterior sobre np.fliplr(). Aquí hay un código que demuestra la construcción de una matriz 1d, transformándola en una matriz 2d, volteándola y luego convirtiéndola de nuevo en una matriz 1d. time.clock() se usará para mantener el tiempo, que se presenta en términos de segundos.

import time 
import numpy as np 

start = time.clock() 
x = np.array(range(3)) 
#transform to 2d 
x = np.atleast_2d(x) 
#flip array 
x = np.fliplr(x) 
#take first (and only) element 
x = x[0] 
#print x 
end = time.clock() 
print end-start 

Con sentencia print sin comentar:

[2 1 0] 
0.00203907123594 

Con sentencia print comentada:

5.59799927506e-05 

Por lo tanto, en términos de eficiencia, creo que eso es decente. Para aquellos de ustedes que aman hacerlo en una línea, aquí está esa forma.

np.fliplr(np.atleast_2d(np.array(range(3))))[0] 
+3

El tiempo de algo con una matriz tan pequeña es bastante inútil. Si quieres comparar cosas, sería mejor usar algo que lleva un tiempo, como 3000 o tal vez más elementos. – Barabas

22

Debido a esto parece no ser tan marcada recibido ninguna respuesta ... La respuesta de Thomas Arildsen debe ser la adecuada uno: sólo tiene que utilizar

np.flipud(your_array) 

si se trata de una matriz 1d (matriz de columnas) .

Con Matrizes hacen

fliplr(matrix) 

si desea revertir filas y flipud(matrix) si quiere dar la vuelta columnas. No es necesario hacer que su matriz de columnas 1d sea una matriz de filas bidimensional (matriz con una capa Ninguno) y luego voltearla.

0

el fin de tener que trabajar con números negativos y una lista larga puede hacer lo siguiente:

b = numpy.flipud(numpy.array(a.split(),float)) 

Dónde flipud es para arra 1d

14

Como se mencionó anteriormente, a[::-1] realmente sólo crea una vista , por lo tanto, es una operación de tiempo constante (y como tal no toma más tiempo a medida que crece la matriz). Si necesita la matriz para ser contiguos (por ejemplo, debido a que se está realizando muchas operaciones vectoriales con él), ascontiguousarray es casi tan rápido como flipup/fliplr:

enter image description here


código para generar la trama :

import numpy 
import perfplot 


perfplot.show(
    setup=lambda n: numpy.random.randint(0, 1000, n), 
    kernels=[ 
     lambda a: a[::-1], 
     lambda a: numpy.ascontiguousarray(a[::-1]), 
     lambda a: numpy.fliplr([a])[0] 
     ], 
    labels=['a[::-1]', 'ascontiguousarray(a[::-1])', 'fliplr'], 
    n_range=[2**k for k in range(20)], 
    xlabel='len(a)', 
    logx=True, 
    logy=True, 
    ) 
Cuestiones relacionadas