Créalo o no, después de perfilar mi código actual, la operación repetitiva de la reversión de matriz numpy se comió una gran parte del tiempo de ejecución. Lo que tengo ahora es el método común basado en la vista:

reversed_arr = arr[::-1]

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

261
nye17 21 jul. 2011 a las 08:58

7 respuestas

La mejor respuesta

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.

¿Vuelve a crear la vista con más frecuencia de la que necesita? Deberías poder 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 parece que sería la forma más rápida de hacer cosas en numpy. Si esto es lo que ya está haciendo, no creo que pueda mejorarlo.

PD Gran discusión de puntos de vista numpy aquí:

Ver en una matriz numpy?

222
Community 23 may. 2017 a las 12:26

Ampliando lo que otros han dicho, daré un breve ejemplo.

Si tienes una matriz 1D ...

>>> import numpy as np
>>> x = np.arange(4) # array([0, 1, 2, 3])
>>> x[::-1] # returns a view
Out[1]: 
array([3, 2, 1, 0])

Pero si está trabajando con una matriz 2D ...

>>> x = np.arange(10).reshape(2, 5)
>>> x
Out[2]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> x[::-1] # returns a view:
Out[3]: array([[5, 6, 7, 8, 9],
               [0, 1, 2, 3, 4]])

Esto en realidad no revierte la matriz.

Debería usar np.flip para invertir los elementos

>>> np.flip(x)
Out[4]: array([[9, 8, 7, 6, 5],
               [4, 3, 2, 1, 0]])

Si desea imprimir los elementos de una matriz uno por uno, use plano junto con flip

>>> for el in np.flip(x).flat:
>>>     print(el, end = ' ')
9 8 7 6 5 4 3 2 1 0
0
John Mil. 16 ene. 2019 a las 21:30

Porque esto parece no estar marcado como respondido todavía ... La respuesta de Thomas Arildsen debería ser la correcta: solo use

np.flipud(your_array) 

Si es una matriz 1d (matriz de columnas).

Con matrices hacer

fliplr(matrix)

Si desea revertir filas y flipud(matrix) si desea voltear columnas. No es necesario hacer que su matriz de columnas 1d sea una matriz de filas bidimensional (matriz con una capa None) y luego voltearla.

39
Hobo 21 jul. 2017 a las 11:28

Como se mencionó anteriormente, a[::-1] realmente solo crea una vista, por lo que es una operación de tiempo constante (y como tal no toma más tiempo a medida que crece la matriz). Si necesita que la matriz sea contigua (por ejemplo, porque está realizando muchas operaciones vectoriales con ella), 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(25)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)
56
Nico Schlömer 31 ago. 2019 a las 16:27

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

Tenga en cuenta que para las matrices 1d, debe engañarlo un poco:

arr1d = np.array(some_sequence)
reversed_arr = np.fliplr([arr1d])[0]
37
Fermi paradox 11 may. 2016 a las 17:17

Ampliaré 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 nuevamente 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 la declaración de impresión sin comentar:

[2 1 0]
0.00203907123594

Con la declaración impresa comentada:

5.59799927506e-05

Entonces, en términos de eficiencia, creo que 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
Fermi paradox 11 may. 2016 a las 17:18

Para que funcione con números negativos y una larga lista, puede hacer lo siguiente:

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

Donde flipud es para 1d array

-1
Taher Khorshidi 19 abr. 2017 a las 08:51