2013-05-10 32 views
80

Betrachten Sie den folgenden Code zu verwenden argsort:Ist es möglich, in absteigender Reihenfolge

avgDists = np.array([1, 8, 6, 9, 4]) 
ids = avgDists.argsort()[:n] 

Diese mich Indizes der n kleinsten Elemente gibt. Ist es möglich, dieselbe argsort in absteigender Reihenfolge zu verwenden, um die Indizes von n höchsten Elementen zu erhalten?

+2

Ist es nicht einfach 'ids = np.array (avgDists) .argsort() [- n:]'? – Jaime

+1

@Jaime: Nein, das funktioniert nicht. "Richtige Antwort" ist "[3, 1, 2]". Deine Zeile produziert '[2, 1, 3]' (wenn n == 3 als Beispiel) – dawg

+1

@drewk Nun, dann mach ''ids = np.array (avgDists) .argsort() [- n:] [: : -1] '. Die Sache ist, eine Kopie der ganzen Liste zu vermeiden, die man erhält, wenn man davor ein '-' hinzufügt. Nicht relevant für das kleine Beispiel des OP könnte für größere Fälle sein. – Jaime

Antwort

80

Wenn Sie einen Array negieren, werden die untersten Elemente der höchsten Elemente und umgekehrt. Daher sind die Indizes der n höchsten Elemente:

(-avgDists).argsort()[:n] 

Ein anderer Weg, um dies zu folgern, wie in der comments erwähnt, ist zu beachten, dass die großen Elemente letzten im argsort kommen. So können Sie aus dem Schweif des argsort lesen Sie die n höchsten Elemente zu finden:

avgDists.argsort()[::-1][:n] 

Beide Methoden sind O (n log n) in Zeitkomplexität, da der argsort Aufruf der dominante Term ist hier. Aber der zweite Ansatz hat einen schönen Vorteil: Er ersetzt die Negation des Arrays durch einen O (1) Schnittpunkt. Wenn Sie mit kleinen Arrays innerhalb von Schleifen arbeiten, können Sie durch die Vermeidung dieser Negation eine Leistungssteigerung erzielen. Wenn Sie mit großen Arrays arbeiten, können Sie die Speichernutzung reduzieren, da die Negation eine Kopie des gesamten Arrays erstellt.

Beachten Sie, dass diese Methoden nicht immer äquivalente Ergebnisse liefern: wenn eine stabile Sortierimplementierung angefordert wird, z. B. argsort, z. Durch Übergeben des Schlüsselwortarguments kind='mergesort' behält die erste Strategie die Sortierstabilität bei, aber die zweite Strategie bricht die Stabilität (d. h. die Positionen der gleichen Elemente werden umgekehrt).

+3

Es ist noch effizienter, vor dem Umkehren zu schneiden, dh, '' np.array (avgDists) .argsort() [: - n] [:: - 1] '' – nedim

+0

Diese Antworten sind nicht gleichwertig, wenn das ursprüngliche Array Nans enthält . In einem solchen Fall scheint die erste Lösung eher am Ende als am Anfang mit nans das natürlichere Ergebnis zu liefern. – feilchenfeldt

+1

Wie vergleichen diese, wenn eine stabile Sortierung gewünscht wird? Vermutlich kehrt die Slicing-Strategie gleiche Items um? – Eric

57

Genau wie Python, daß [::-1] das Array gibt wieder umkehrt, indem argsort() und [:n], dass im letzten n Elemente:

>>> avgDists=np.array([1, 8, 6, 9, 4]) 
>>> n=3 
>>> ids = avgDists.argsort()[::-1][:n] 
>>> ids 
array([3, 1, 2]) 

Der Vorteil dieser Methode ist, dass ids a view von avgDists ist:

>>> ids.flags 
    C_CONTIGUOUS : False 
    F_CONTIGUOUS : False 
    OWNDATA : False 
    WRITEABLE : True 
    ALIGNED : True 
    UPDATEIFCOPY : False 

(Die Angabe 'OWNDATA' ist falsch, dies ist eine Ansicht, keine Kopie)

Ein anderer Weg, dies zu tun, ist so etwas wie:

(-avgDists).argsort()[:n] 

Das Problem ist, dass die Art und Weise das funktioniert jedes Element im Array negativ zu erstellen ist:

>>> (-avgDists) 
array([-1, -8, -6, -9, -4]) 

und erstellt eine Kopie, dies zu tun :

>>> (-avgDists_n).flags['OWNDATA'] 
True 

Also jeder, wenn Sie Zeit, auch bei dieser sehr kleinen Datensatz:

>>> import timeit 
>>> timeit.timeit('(-avgDists).argsort()[:3]', setup="from __main__ import avgDists") 
4.2879798610229045 
>>> timeit.timeit('avgDists.argsort()[::-1][:3]', setup="from __main__ import avgDists") 
2.8372560259886086 

Die Ansicht Verfahren ist wesentlich schneller

+2

Diese Antwort ist gut, aber ich fühle, dass Ihre Formulierung falsch darstellt die echten Leistungsmerkmale: * "Auch mit diesem sehr kleinen Datensatz ist die View-Methode wesentlich schneller" *. In Wirklichkeit ist die Negation * O (n) * und der Argsort ist * O (n log n) *. Dies bedeutet, dass die Zeitdiskrepanz * für größere Datensätze * abnimmt * - der * O (n log n) * -Term dominiert, jedoch ist Ihr Vorschlag eine Optimierung des * O (n) * -Teils. Die Komplexität bleibt also gleich, und gerade für diesen kleinen Datensatz * sehen wir signifikante Unterschiede. – wim

3

Sie könnten eine Kopie des Arrays erstellen und dann jedes Element mit -1 multiplizieren.
Als Effekt würden die vorher größten Elemente zum kleinsten werden.
Die Indezes der n kleinsten Elemente in der Kopie sind die n größten Elemente im Original.

1

Anstatt np.argsort zu verwenden, können Sie np.argpartition verwenden - wenn Sie nur die Indizes der niedrigsten/höchsten n Elemente benötigen.

Das ist nicht das gesamte Array zu sortieren erfordert, sondern nur den Teil, den Sie brauchen, aber beachten Sie, dass die „Ordnung in Ihrer Partition“ nicht definiert ist, also, während es die richtigen Indizes gibt sie nicht richtig bestellt werden könnten:

>>> avgDists = [1, 8, 6, 9, 4] 
>>> np.array(avgDists).argpartition(2)[:2] # indices of lowest 2 items 
array([0, 4], dtype=int64) 

>>> np.array(avgDists).argpartition(-2)[-2:] # indices of highest 2 items 
array([1, 3], dtype=int64) 
1

Sie können mit der Flip-Befehlen numpy.flipud() oder numpy.fliplr() die Indizes erhalten in absteigender Reihenfolge nach mit dem Befehl argsort Sortierung. Das ist, was ich normalerweise tue.

0

Eine andere Möglichkeit besteht darin, nur ein '-' im Argument für argsort zu verwenden, wie in: "df [np.argsort (-df [:, 0])]" vorausgesetzt, df ist der Datenrahmen und Sie möchten sortieren es durch die erste Spalte (dargestellt durch die Spaltennummer "0"). Ändern Sie den Spaltennamen entsprechend. Natürlich muss die Spalte numerisch sein.

1

Mit Ihrem Beispiel:

avgDists = np.array([1, 8, 6, 9, 4]) 

Erhalten Indizes n Maximalwerte:

ids = np.argpartition(avgDists, -n)[-n:] 

sortieren sie in absteigender Reihenfolge:

ids = ids[np.argsort(avgDists[ids])[::-1]] 

Ergebnisse erhalten (für n = 4) :

Verwandte Themen