Ordinamento efficiente di un array numpy in ordine decrescente?


121

Sono sorpreso che questa domanda specifica non sia stata posta prima, ma davvero non l'ho trovata su SO né sulla documentazione di np.sort.

Supponiamo di avere un array numpy casuale che contiene numeri interi, ad esempio:

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

Se lo ordino, ottengo l'ordine crescente per impostazione predefinita:

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

ma voglio che la soluzione venga ordinata in ordine decrescente .

Ora, so che posso sempre fare:

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

ma questa ultima affermazione è efficiente ? Non crea una copia in ordine crescente e quindi inverte questa copia per ottenere il risultato in ordine inverso? Se è davvero così, esiste un'alternativa efficiente? Non sembra che np.sortaccetta parametri per modificare il segno dei confronti nell'operazione di ordinamento per ottenere le cose in ordine inverso.

Risposte:


139

temp[::-1].sort()ordina l'array in posizione, mentre np.sort(temp)[::-1]crea un nuovo array.

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

30
Grazie, ma come fa a temp[::-1].sort()sapere che deve ordinare in ordine inverso ?? Il modo in cui lo leggo è: inverti l'array originale, quindi ordinalo (in ordine crescente). Perché invertire l'array originale (arrivando in ordine casuale) e quindi ordinarlo in ordine crescente restituirebbe l'array in ordine inverso?
Amelio Vazquez-Reina

14
Questo comportamento è documentato, in quanto è piuttosto intuitivo.
ebarr

18
Sembra che funzioni perché [::-1]semplicemente dice a numpy di iterare sull'array all'indietro, piuttosto che riordinare l'array. Quindi, quando si verifica l'ordinamento sul posto, in realtà ordina in ordine crescente e sposta i bit, ma lascia intatta la parte dell'iterazione all'indietro.
perimosocordiae

45
Con a=np.array((...))l'idioma a[::-1]non si inverte nulla, è solo una nuova vista sugli stessi dati, più precisamente una vista speculare. Il metodo a[::-1].sort() opera sull'immagine speculare , implicando che quando si sortsposta a sinistra un elemento più piccolo nella sua immagine speculare, in realtà lo sta spostando a destra nel blocco di memoria reale adell'array. La vista speculare è ordinata in ordine crescente, i dati reali sono ordinati in ordine decrescente. Provalo a casa da solo, con alcune monete diverse e uno specchio!
gboffi

30
Questo dovrebbe davvero essere aggiunto come parametro leggibile, come np.sort(temp,order='descending')piuttosto che richiedere questo tipo di hack
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])

2
Risposta migliore: breve e dolce, e non è necessaria alcuna conoscenza di axiscui è np.sortstata applicata.
Luke Davis

2
Questo è diverso dal fatto np.sort(temp)[::-1]che pone nans sul retro dell'array invece che sul davanti. Che sia positivo o negativo è in discussione ..
Ben

15

Per gli array brevi suggerisco di utilizzare np.argsort()trovando gli indici dell'array negatived ordinato, che è leggermente più veloce dell'inversione dell'array ordinato:

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

a[np.argsort(-a)]è probabilmente l'approccio migliore a tutti gli altri in questa pagina. Nessuna inversione di -1 passaggio e un segno meno in meno a cui pensare.
Jarad

8

Purtroppo quando si dispone di un array complesso, np.sort(temp)[::-1]funziona solo correttamente. Gli altri due metodi qui menzionati non sono efficaci.


@ anishtain4: Con "array complesso", intendevi un array di numeri complessi? O intendevi un array con un altro tipo di complessità (in tal caso, specifica quale tipo di complessità). In entrambi i casi, credo che potresti approfondire ulteriormente la tua risposta, approfondendo il modo in cui gli altri metodi potrebbero fallire. Grazie.
Fountainhead

@ fountainhead intendo la matrice di numeri complessi. Poiché è una vecchia domanda, non ricordo il mio caso di prova da allora per elaborare di più.
anishtain

7

Fai attenzione alle dimensioni.

Permettere

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

Reverse completo

z = x[-I]
z = -np.sort(-x)
z = np.flip(y)
  • flipmodificato in 1.15, versioni precedenti richieste . Soluzione: .1.14 axispip install --upgrade numpy

Prima dimensione invertita

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

Seconda dimensione invertita

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

analisi

Test su un array 100 × 10 × 10 1000 volte.

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

Ciò è dovuto principalmente alla reindicizzazione piuttosto che 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)

6

Ciao, stavo cercando una soluzione per invertire l'ordinamento di un array numpy bidimensionale e non sono riuscito a trovare nulla che funzionasse, ma penso di essere incappato in una soluzione che sto caricando nel caso in cui qualcuno si trovi nella stessa barca.

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

np.sort ordina in modo crescente che non è quello che vuoi, ma il comando fliplr capovolge le righe da sinistra a destra! Sembra funzionare!

Spero che ti aiuti!

Immagino sia simile al suggerimento su -np.sort (-a) sopra, ma sono stato scoraggiato dal commento che non sempre funziona. Forse anche la mia soluzione non funzionerà sempre, tuttavia l'ho testata con alcuni array e sembra essere OK.


1

È possibile prima ordinare l'array (crescente per impostazione predefinita) e quindi applicare np.flip () ( https://docs.scipy.org/doc/numpy/reference/generated/numpy.flip.html )

FYI Funziona anche con oggetti datetime.

Esempio:

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

Per coloro che hanno NaN nei loro array, fate attenzione, i vari metodi proposti producono risultati diversi. Ad esempio, se x = np.array([2,3,np.nan,1,0]) l' np.flip(np.sort(x))approccio produce [nan 3. 2. 1. 0.], mentre l' -np.sort(-x)approccio produce [3. 2. 1. 0. nan].
Uwe Mayer

1

Ecco un trucco veloce

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]

-3

suggerisco di usare questo ...

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

per esempio:

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

Quindi il tuo risultato:

[ 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. ]

1
Come risolve il problema? Stai solo la creazione di un nuovo array completamente estranei, (discendente), che - tra l'altro - potrebbe essere fatto in modo più efficiente: np.arange(20-0.5, 10-0.5, -0.5). Ma questa è una storia diversa e potrebbe essere, a causa della peggiore leggibilità, discutibile. Un array di input non è affatto ordinato
Daniel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.