Invierta una matriz NumPy de manera eficiente

6 minutos de lectura

avatar de usuario
nye17

¿Cómo invierto una matriz NumPy de manera eficiente? Actualmente estoy tomando un reverso vista de eso:

reversed_arr = arr[::-1]

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

    –Joe Kington

    21 de julio de 2011 a las 5:14

  • si, de hecho, arr es una matriz numpy.

    – nye17

    21 de julio de 2011 a las 5:15

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

    –Joe Kington

    21 de julio de 2011 a las 5:18


  • Bueno, ¿tienes que ejecutarlo necesariamente dentro de un bucle? En algunos casos, es mejor hacer una matriz numpy con millones de elementos y luego operar en toda la matriz. Incluso si está utilizando un método de diferencias finitas o algo similar donde el resultado depende del resultado anterior, a veces puede hacer esto. (Énfasis en a veces…) En cualquier caso, si la velocidad es el objetivo principal, Fortran sigue siendo el rey. f2py ¡es tu amigo! A menudo vale la pena escribir partes críticas de rendimiento de un algoritmo (especialmente en computación científica) en otro idioma y llamarlo desde python. ¡Buena suerte!

    –Joe Kington

    21 de julio de 2011 a las 5:54

  • @berto. Es más lento ya que es un envoltorio para arr[::-1]: github.com/numpy/numpy/blob/master/numpy/lib/twodim_base.py. Buscar def flipud. La función tiene literalmente cuatro líneas de largo.

    – Físico loco

    1 de abril de 2016 a las 5:14

avatar de usuario
steveha

reversed_arr = arr[::-1]

da un revés vista en la matriz original arr. Cualquier cambio realizado en la matriz original arr también será inmediatamente visible en reversed_arr. Los búferes de datos subyacentes para arr y reversed_arr son compartidopor lo que la creación de esta vista siempre es instantánea y no requiere ninguna asignación de memoria adicional ni copia del contenido de la matriz.

Consulte también esta discusión sobre las vistas NumPy: ¿Cómo creo una vista en una matriz NumPy?


Posibles soluciones a problemas de rendimiento con respecto a las vistas

¿Está recreando la vista con más frecuencia de la necesaria? 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 en numpy, pero parece que sería la forma más rápida de hacer las cosas en numpy. Si esto es lo que ya estás haciendo, no creo que puedas mejorarlo.

  • ¿Ayuda crear un objeto de división y luego reutilizarlo en muchas matrices?

    – endolito

    16 mayo 2014 a las 14:47

  • De hecho, 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. Repetiblemente 43,4 ms frente a 44,3 ms para un bucle de 1000000)

    – endolito

    16 mayo 2014 a las 15:02


  • Que es look_at función se supone que debe hacer?

    – mrgloom

    12 de marzo de 2019 a las 18:13

  • @mrgloom Se supone que representa cualquier tarea que analice los datos. El punto del ejemplo era mostrar que la vista reversed_arr todavía se puede utilizar después de que se cambiaron los datos subyacentes. Escribir nuevos valores en la matriz no invalida la vista. En realidad, también podría usar la vista para escribir nuevos valores en la matriz. reversed_arr[0] = 99 establecería el último elemento de la matriz en 99, lo mismo que arr[-1] = 99 haría.

    – steveha

    20 de marzo de 2019 a las 8:33

avatar de usuario
Nico Schlömer

a[::-1]

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 tan rápido como flipud/fliplr:

ingrese la descripción de la imagen aquí


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)",
)

  • perfplot requiere al menos Python 3.6 porque usa f-strings (interpolación de cadenas literales)

    – cincof

    13 de mayo de 2020 a las 8:52

avatar de usuario
zauberfein

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 matrizes hacer

fliplr(matrix)

si desea invertir 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 Ninguna) y luego voltearla.

avatar de usuario
dentadura44

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]

Ampliaré la respuesta anterior sobre np.fliplr(). Aquí hay un código que demuestra cómo construir una matriz 1d, transformarla en una matriz 2d, voltearla y luego volver a convertirla en una matriz 1d. time.clock() se utilizará 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 declaración de impresión sin comentar:

[2 1 0]
0.00203907123594

Con 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]

  • Programar algo con una matriz tan pequeña es bastante inútil. Si desea comparar cosas, sería mejor usar algo que tome un tiempo, como 3000 o incluso más elementos.

    – bajo

    13 mayo 2016 a las 15:09

avatar de usuario
Victoria

La notación de corte basada en análogo a np.flip sería [::-1,::-1]

a = np.array([[1., 2.], [3., 4.], [5, 6]])
print(a)

out: [[1. 2.]
      [3. 4.]
      [5. 6.]]

b=a[::-1,::-1]
print(b)

out: [[1. 2.]
      [3. 4.]
      [5. 6.]]

  • Programar algo con una matriz tan pequeña es bastante inútil. Si desea comparar cosas, sería mejor usar algo que tome un tiempo, como 3000 o incluso más elementos.

    – bajo

    13 mayo 2016 a las 15:09

avatar de usuario
Juan Mil.

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 invierte Matrix.

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 flat junto con flip

>>> for el in np.flip(x).flat:
>>>     print(el, end = ' ')
9 8 7 6 5 4 3 2 1 0

  • Creo que también podrías usar x […,::-1] para crear una vista invertida de una matriz multidimensional sin recurrir a np.flip, como se demuestra aquí stackoverflow.com/questions/7416170/…

    – phntm

    17 oct 2020 a las 6:05

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad