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.

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

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

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

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

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.


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

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]

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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.