Ein numpy Array effizient in absteigender Reihenfolge sortieren?

119

Ich bin überrascht, dass diese spezielle Frage noch nicht gestellt wurde, aber ich habe sie weder in SO noch in der Dokumentation von gefunden np.sort.

Angenommen, ich habe ein zufälliges Numpy-Array mit ganzen Zahlen, z.

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

Wenn ich es sortiere, erhalte ich standardmäßig aufsteigende Reihenfolge:

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

Ich möchte jedoch, dass die Lösung in absteigender Reihenfolge sortiert wird.

Jetzt weiß ich, dass ich immer tun kann:

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

Aber ist diese letzte Aussage effizient ? Erstellt es keine Kopie in aufsteigender Reihenfolge und kehrt diese Kopie dann um, um das Ergebnis in umgekehrter Reihenfolge zu erhalten? Wenn dies tatsächlich der Fall ist, gibt es eine effiziente Alternative? Es sieht nicht so aus, als würde es np.sortParameter akzeptieren, um das Vorzeichen der Vergleiche in der Sortieroperation zu ändern und die Dinge in umgekehrter Reihenfolge zu erhalten.

Amelio Vazquez-Reina
quelle

Antworten:

138

temp[::-1].sort()sortiert das Array an Ort und Stelle, während np.sort(temp)[::-1]ein neues Array erstellt wird.

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
quelle
30
Danke, aber woher weiß man temp[::-1].sort(), dass es in umgekehrter Reihenfolge sortieren muss? Ich lese es so: Kehre das ursprüngliche Array um und sortiere es dann (in aufsteigender Reihenfolge). Warum würde das Umkehren des ursprünglichen Arrays (in zufälliger Reihenfolge) und das anschließende Sortieren in aufsteigender Reihenfolge das Array in umgekehrter Reihenfolge zurückgeben?
Amelio Vazquez-Reina
14
Ist dieses Verhalten dokumentiert, da es ziemlich unintuitiv ist?
ebarr
18
Dies [::-1]scheint zu funktionieren, da numpy einfach angewiesen wird, das Array rückwärts zu durchlaufen, anstatt das Array tatsächlich neu zu ordnen. Wenn also die In-Place-Sortierung erfolgt, sortiert sie tatsächlich in aufsteigender Reihenfolge und verschiebt die Bits, lässt jedoch den Teil der Rückwärtsiteration unberührt.
Perimosocordiae
45
Da a=np.array((...))die Redewendung a[::-1]nichts umkehrt, handelt es sich lediglich um eine neue Ansicht derselben Daten, insbesondere um eine Spiegelansicht. Das Verfahren a[::-1].sort() arbeitet mit dem gespiegelten Bild , was bedeutet, dass wenn ein kleineres Element in seinem gespiegelten Bild sortnach links verschoben wird, es in Wirklichkeit im realen Speicherblock des Arrays nach rechtsa verschoben wird. Die gespiegelte Ansicht ist in aufsteigender Reihenfolge sortiert, die realen Daten sind in absteigender Reihenfolge sortiert. Probieren Sie es zu Hause aus, mit verschiedenen Münzen und einem Spiegel!
Gboffi
29
Dies sollte wirklich als lesbarer Parameter hinzugefügt werden, np.sort(temp,order='descending')anstatt diese Art von Hacks zu erfordern
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
quelle
2
Beste Antwort - kurz und süß, und kein Wissen über die axisan die np.sortangewandt wurde notwendig.
Luke Davis
2
Dies unterscheidet sich davon, np.sort(temp)[::-1]dass nans auf der Rückseite des Arrays anstelle der Vorderseite platziert wird. Ob das gut oder schlecht ist, steht zur Debatte.
Ben
15

Für kurze Arrays schlage ich vor np.argsort(), die Indizes des sortierten negierten Arrays zu ermitteln, was etwas schneller ist als das Umkehren des sortierten Arrays:

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
Kasramvd
quelle
a[np.argsort(-a)]ist wahrscheinlich der beste Ansatz für alle anderen auf dieser Seite. Keine Umkehrung von -1 Schritten und ein Minuszeichen weniger zum Nachdenken.
Jarad
8

Leider np.sort(temp)[::-1]funktioniert ein komplexes Array nur ordnungsgemäß. Die beiden anderen hier genannten Methoden sind nicht wirksam.

anishtain4
quelle
@ anishtain4: Mit "komplexes Array" meinten Sie ein Array komplexer Zahlen? Oder meinten Sie ein Array mit einer anderen Art von Komplexität (wenn ja, geben Sie bitte an, welche Art von Komplexität vorliegt). Ich bin der Meinung, dass Sie in beiden Fällen Ihre Antwort näher erläutern könnten, indem Sie untersuchen, wie die anderen Methoden fehlschlagen könnten. Vielen Dank.
Brunnenkopf
@Fountainhead Ich meine das Array komplexer Zahlen. Da es sich um eine alte Frage handelt, erinnere ich mich nicht an meinen Testfall, um mehr zu erläutern.
Anishtain4
7

Seien Sie vorsichtig mit den Abmessungen.

Lassen

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

Volle Umkehrung

z = x[-I]
z = -np.sort(-x)
z = np.flip(y)
  • flipgeändert in 1.15, frühere Versionen erforderlich . Lösung : .1.14 axispip install --upgrade numpy

Erste Dimension umgekehrt

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

Zweite Dimension umgekehrt

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

Testen

1000-maliges Testen auf einem 100 × 10 × 10-Array.

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

Dies ist hauptsächlich auf die Neuindizierung und nicht auf die Neuindizierung zurückzuführen 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. West
quelle
6

Hallo, ich habe nach einer Lösung gesucht, um das Sortieren eines zweidimensionalen Numpy-Arrays umzukehren, und ich konnte nichts finden, was funktioniert hat, aber ich glaube, ich bin auf eine Lösung gestoßen, die ich hochlade, nur für den Fall, dass sich jemand im selben Boot befindet.

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

np.sort sortiert aufsteigend, was nicht das ist, was Sie wollen, aber der Befehl fliplr dreht die Zeilen von links nach rechts! Scheint zu funktionieren!

Hoffe es hilft dir!

Ich denke, es ist ähnlich wie der Vorschlag über -np.sort (-a) oben, aber ich wurde durch den Kommentar davon abgehalten, dass es nicht immer funktioniert. Vielleicht funktioniert meine Lösung auch nicht immer, aber ich habe sie mit ein paar Arrays getestet und scheint in Ordnung zu sein.

Naz
quelle
1

Sie können das Array zuerst sortieren (standardmäßig aufsteigend) und dann np.flip () anwenden ( https://docs.scipy.org/doc/numpy/reference/generated/numpy.flip.html ).

Zu Ihrer Information Es funktioniert auch mit Datetime-Objekten.

Beispiel:

    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
quelle
Für diejenigen, die NaN in ihren Arrays haben, seien Sie vorsichtig, verschiedene vorgeschlagene Methoden führen zu unterschiedlichen Ergebnissen. Zum Beispiel, wenn x = np.array([2,3,np.nan,1,0]) dann der np.flip(np.sort(x))Ansatz [nan 3. 2. 1. 0.] -np.sort(-x)ergibt , während der Ansatz [3. 2. 1. 0. nan] ergibt.
Uwe Mayer
1

Hier ist ein kurzer Trick

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
quelle
-3

Ich schlage vor, dies zu verwenden ...

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

beispielsweise:

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

Dann Ihr Resault:

[ 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
quelle
1
Wie löst dies das Problem? Sie erstellen lediglich ein völlig unabhängiges, neues (absteigendes) Array, das übrigens effizienter erstellt werden könnte : np.arange(20-0.5, 10-0.5, -0.5). Aber das ist eine andere Geschichte und kann wegen der schlechteren Lesbarkeit umstritten sein. Ein Eingabearray ist überhaupt nicht sortiert
Daniel