¿Ordenando eficientemente una matriz numpy en orden descendente?

121

Me sorprende que esta pregunta específica no se haya hecho antes, pero realmente no la encontré en SO ni en la documentación de np.sort.

Digamos que tengo una matriz numérica aleatoria con números enteros, por ejemplo:

> temp = np.random.randint(1,10, 10)    
> temp
array([2, 4, 7, 4, 2, 2, 7, 6, 4, 4])

Si lo ordeno, obtengo un orden ascendente por defecto:

> np.sort(temp)
array([2, 2, 2, 4, 4, 4, 4, 6, 7, 7])

pero quiero que la solución se ordene en orden descendente .

Ahora, sé que siempre puedo hacer:

reverse_order = np.sort(temp)[::-1]

pero, ¿esta última afirmación es eficaz ? ¿No crea una copia en orden ascendente y luego invierte esta copia para obtener el resultado en orden inverso? Si este es realmente el caso, ¿existe una alternativa eficiente? No parece que np.sortacepte parámetros para cambiar el signo de las comparaciones en la operación de clasificación para poner las cosas en orden inverso.

Amelio Vázquez-Reina
fuente

Respuestas:

139

temp[::-1].sort()ordena la matriz en su lugar, mientras que np.sort(temp)[::-1]crea una nueva matriz.

In [25]: temp = np.random.randint(1,10, 10)

In [26]: temp
Out[26]: array([5, 2, 7, 4, 4, 2, 8, 6, 4, 4])

In [27]: id(temp)
Out[27]: 139962713524944

In [28]: temp[::-1].sort()

In [29]: temp
Out[29]: array([8, 7, 6, 5, 4, 4, 4, 4, 2, 2])

In [30]: id(temp)
Out[30]: 139962713524944
Padraic Cunningham
fuente
30
Gracias, pero ¿cómo temp[::-1].sort()sabe que tiene que ordenar en orden inverso? La forma en que lo leo es: invierta la matriz original y luego ordénela (en orden ascendente). ¿Por qué invertir la matriz original (que viene en un orden aleatorio) y luego ordenarla en orden ascendente devolvería la matriz en orden inverso?
Amelio Vazquez-Reina
14
¿Está documentado este comportamiento, ya que es bastante poco intuitivo?
ebarr
18
Esto parece que funciona porque [::-1]simplemente le dice a numpy que repita la matriz hacia atrás, en lugar de reordenar la matriz. Entonces, cuando ocurre la ordenación en el lugar, en realidad ordena en orden ascendente y mueve los bits, pero deja intacta la parte de iteración hacia atrás.
perimosocordiae
45
Con a=np.array((...))el idioma a[::-1]no revierte nada, es solo una nueva vista sobre los mismos datos, más específicamente una vista en espejo. El método a[::-1].sort() opera en la imagen reflejada , lo que implica que cuando se sortmueve hacia la izquierda un elemento más pequeño en su imagen reflejada, en realidad lo está moviendo hacia la derecha en el bloque de memoria real de la amatriz. La vista reflejada se ordena en orden ascendente, los datos reales se ordenan en orden descendente. ¡Pruébalo tú mismo en casa, con monedas diferentes y un espejo!
gboffi
30
Esto realmente debería agregarse como un parámetro legible, como en np.sort(temp,order='descending')lugar de requerir este tipo de trucos
Nathan
92
>>> a=np.array([5, 2, 7, 4, 4, 2, 8, 6, 4, 4])

>>> np.sort(a)
array([2, 2, 4, 4, 4, 4, 5, 6, 7, 8])

>>> -np.sort(-a)
array([8, 7, 6, 5, 4, 4, 4, 4, 2, 2])
Mike O'Connor
fuente
2
La mejor respuesta: breve y dulce, y no es necesario saber axisa qué np.sortse aplica.
Luke Davis
2
Esto es diferente a np.sort(temp)[::-1]que coloca nans en la parte posterior de la matriz en lugar de en el frente. Si eso es bueno o malo está en debate ..
Ben
15

Para arreglos cortos, sugiero usarlo np.argsort()buscando los índices del arreglo negativo ordenado, que es un poco más rápido que invertir el arreglo ordenado:

In [37]: temp = np.random.randint(1,10, 10)

In [38]: %timeit np.sort(temp)[::-1]
100000 loops, best of 3: 4.65 µs per loop

In [39]: %timeit temp[np.argsort(-temp)]
100000 loops, best of 3: 3.91 µs per loop
Kasravnd
fuente
a[np.argsort(-a)]es probablemente el mejor enfoque para cualquier otro en esta página. No hay retroceso de -1 paso y un signo menos menos en el que pensar.
Jarad
8

Desafortunadamente, cuando tiene una matriz compleja, solo np.sort(temp)[::-1]funciona correctamente. Los otros dos métodos mencionados aquí no son efectivos.

anishtain4
fuente
@ anishtain4: Por "matriz compleja", ¿te refieres a una matriz de números complejos? ¿O se refería a una matriz con algún otro tipo de complejidad (si es así, especifique qué tipo de complejidad)? En cualquier caso, creo que podría desarrollar un poco más su respuesta, analizando cómo pueden fallar los otros métodos. Gracias.
manantial
@fountainhead Me refiero a la matriz de números complejos. Como es una pregunta antigua, no recuerdo mi caso de prueba de entonces para elaborar más.
anishtain4
7

Tenga cuidado con las dimensiones.

Dejar

x  # initial numpy array
I = np.argsort(x) or I = x.argsort() 
y = np.sort(x)    or y = x.sort()
z  # reverse sorted array

Totalmente inverso

z = x[-I]
z = -np.sort(-x)
z = np.flip(y)
  • flipcambiado en 1.15, se requieren versiones anteriores . Solución: .1.14 axispip install --upgrade numpy

Primera dimensión invertida

z = y[::-1]
z = np.flipud(y)
z = np.flip(y, axis=0)

Segunda dimensión invertida

z = y[::-1, :]
z = np.fliplr(y)
z = np.flip(y, axis=1)

Pruebas

Prueba en una matriz de 100 × 10 × 10 1000 veces.

Method       | Time (ms)
-------------+----------
y[::-1]      | 0.126659  # only in first dimension
-np.sort(-x) | 0.133152
np.flip(y)   | 0.121711
x[-I]        | 4.611778

x.sort()     | 0.024961
x.argsort()  | 0.041830
np.flip(x)   | 0.002026

Esto se debe principalmente a la reindexación más que a argsort.

# Timing code
import time
import numpy as np


def timeit(fun, xs):
    t = time.time()
    for i in range(len(xs)):  # inline and map gave much worse results for x[-I], 5*t
        fun(xs[i])
    t = time.time() - t
    print(np.round(t,6))

I, N = 1000, (100, 10, 10)
xs = np.random.rand(I,*N)
timeit(lambda x: np.sort(x)[::-1], xs)
timeit(lambda x: -np.sort(-x), xs)
timeit(lambda x: np.flip(x.sort()), xs)
timeit(lambda x: x[-x.argsort()], xs)
timeit(lambda x: x.sort(), xs)
timeit(lambda x: x.argsort(), xs)
timeit(lambda x: np.flip(x), xs)
A. Oeste
fuente
6

Hola, estaba buscando una solución para revertir la clasificación de una matriz numérica bidimensional, y no pude encontrar nada que funcionara, pero creo que me encontré con una solución que estoy cargando en caso de que alguien esté en el mismo barco.

x=np.sort(array)
y=np.fliplr(x)

np.sort ordena en forma ascendente que no es lo que desea, pero el comando fliplr cambia las filas de izquierda a derecha. ¡Parece funcionar!

¡Espero que te ayude!

Supongo que es similar a la sugerencia sobre -np.sort (-a) anterior, pero me desanimé al comentar que no siempre funciona. Quizás mi solución no siempre funcione, sin embargo, la he probado con algunas matrices y parece estar bien.

Naz
fuente
1

Primero puede ordenar la matriz (ascendente de forma predeterminada) y luego aplicar np.flip () ( https://docs.scipy.org/doc/numpy/reference/generated/numpy.flip.html )

FYI También funciona con objetos de fecha y hora.

Ejemplo:

    x = np.array([2,3,1,0]) 
    x_sort_asc=np.sort(x) 
    print(x_sort_asc)

    >>> array([0, 1, 2, 3])

    x_sort_desc=np.flip(x_sort_asc) 
    print(x_sort_desc)

    >>> array([3,2,1,0])
maleckicoa
fuente
Para aquellos que tienen NaN en sus matrices, tenga cuidado, varios métodos propuestos producen resultados diferentes. Por ejemplo, si x = np.array([2,3,np.nan,1,0]) el np.flip(np.sort(x))enfoque produce [nan 3. 2. 1. 0.], mientras que el -np.sort(-x)enfoque produce [3. 2. 1. 0. nan].
Uwe Mayer
1

Aquí hay un truco rápido

In[3]: import numpy as np
In[4]: temp = np.random.randint(1,10, 10)
In[5]: temp
Out[5]: array([5, 4, 2, 9, 2, 3, 4, 7, 5, 8])

In[6]: sorted = np.sort(temp)
In[7]: rsorted = list(reversed(sorted))
In[8]: sorted
Out[8]: array([2, 2, 3, 4, 4, 5, 5, 7, 8, 9])

In[9]: rsorted
Out[9]: [9, 8, 7, 5, 5, 4, 4, 3, 2, 2]
Don Coder
fuente
-3

sugiero usar esto ...

np.arange(start_index, end_index, intervals)[::-1]

por ejemplo:

np.arange(10, 20, 0.5)
np.arange(10, 20, 0.5)[::-1]

Entonces tu resultado:

[ 19.5,  19. ,  18.5,  18. ,  17.5,  17. ,  16.5,  16. ,  15.5,
    15. ,  14.5,  14. ,  13.5,  13. ,  12.5,  12. ,  11.5,  11. ,
    10.5,  10. ]
morteza omidipoor
fuente
1
¿Cómo soluciona esto el problema? No eres más que la creación de una nueva matriz (descendente) por completo, sin relación, que - por cierto - se podría hacer de una manera más eficiente: np.arange(20-0.5, 10-0.5, -0.5). Pero esa es una historia diferente y puede ser, debido a la peor legibilidad, discutible. Una matriz de entrada no está ordenada en absoluto
Daniel