Wie kann ich ein Array in NumPy nach der n-ten Spalte sortieren?
Zum Beispiel,
a = array([[9, 2, 3],
[4, 5, 6],
[7, 0, 5]])
Ich möchte Zeilen nach der zweiten Spalte sortieren, so dass ich zurückkomme:
array([[7, 0, 5],
[9, 2, 3],
[4, 5, 6]])
Ich nehme an, das funktioniert: "a[a[:,1].argsort()]`
Dies zeigt die zweite Spalte von "a" an und sortiert sie entsprechend.
@steve's ist eigentlich die eleganteste Art, dies zu tun.
Für den "richtigen" Weg siehe das Argument des Schlüsselworts order von numpy.ndarray.sort
Allerdings müssen Sie Ihr Array als ein Array mit Feldern (ein strukturiertes Array) betrachten.
Der "korrekte" Weg ist ziemlich hässlich, wenn Sie Ihr Array nicht ursprünglich mit Feldern definiert haben...
Als schnelles Beispiel, um es zu sortieren und eine Kopie zurückzugeben:
In [1]: import numpy as np
In [2]: a = np.array([[1,2,3],[4,5,6],[0,0,1]])
In [3]: np.sort(a.view('i8,i8,i8'), order=['f1'], axis=0).view(np.int)
Out[3]:
array([[0, 0, 1],
[1, 2, 3],
[4, 5, 6]])
Um sie an Ort und Stelle zu sortieren:
In [6]: a.view('i8,i8,i8').sort(order=['f1'], axis=0) #<-- returns None
In [7]: a
Out[7]:
array([[0, 0, 1],
[1, 2, 3],
[4, 5, 6]])
@Steve's ist wirklich der eleganteste Weg, es zu tun, soweit ich weiß...
Der einzige Vorteil dieser Methode ist, dass das Argument "order" eine Liste der Felder ist, nach denen die Suche sortiert werden soll. Sie können zum Beispiel nach der zweiten Spalte, dann nach der dritten Spalte und dann nach der ersten Spalte sortieren, indem Sie order=['f1','f2','f0'] angeben.
Sie können nach mehreren Spalten gemäß der Methode von Steve Tjoa's sortieren, indem Sie eine stabile Sortierung wie Mergesort verwenden und die Indizes von der am wenigsten signifikanten zu den signifikantesten Spalten sortieren:
a = a[a[:,2].argsort()] # First sort doesn't need to be stable.
a = a[a[:,1].argsort(kind='mergesort')]
a = a[a[:,0].argsort(kind='mergesort')]
Dabei wird nach Spalte 0, dann 1, dann 2 sortiert.
Von der Python-Dokumentation Wiki, ich denke, Sie können tun:
a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]);
a = sorted(a, key=lambda a_entry: a_entry[1])
print a
Die Ausgabe ist:
[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]
Für den Fall, dass jemand die Sortierung an einem kritischen Teil seiner Programme nutzen möchte, hier's ein Leistungsvergleich für die verschiedenen Vorschläge:
import numpy as np
table = np.random.rand(5000, 10)
%timeit table.view('f8,f8,f8,f8,f8,f8,f8,f8,f8,f8').sort(order=['f9'], axis=0)
1000 loops, best of 3: 1.88 ms per loop
%timeit table[table[:,9].argsort()]
10000 loops, best of 3: 180 µs per loop
import pandas as pd
df = pd.DataFrame(table)
%timeit df.sort_values(9, ascending=True)
1000 loops, best of 3: 400 µs per loop
Es sieht also so aus, als ob die Indizierung mit [argsort][1] die bisher schnellste Methode ist...
[1]: http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.argsort.html
Von [der NumPy-Mailingliste][1], hier's eine weitere Lösung:
>>> a
array([[1, 2],
[0, 0],
[1, 0],
[0, 2],
[2, 1],
[1, 0],
[1, 0],
[0, 0],
[1, 0],
[2, 2]])
>>> a[np.lexsort(np.fliplr(a).T)]
array([[0, 0],
[0, 0],
[0, 2],
[1, 0],
[1, 0],
[1, 0],
[1, 0],
[1, 2],
[2, 1],
[2, 2]])
[1]: http://mail.scipy.org/pipermail/numpy-discussion/2008-December/039332.html
Ich hatte ein ähnliches Problem.
Mein Problem:
Ich möchte eine SVD berechnen und muss meine [Eigenwerte][1] in absteigender Reihenfolge sortieren. Aber ich möchte die Zuordnung zwischen Eigenwerten und Eigenvektoren beibehalten. Meine Eigenwerte standen in der ersten Zeile und der entsprechende Eigenvektor darunter in der gleichen Spalte.
Ich möchte also ein zweidimensionales Array spaltenweise nach der ersten Zeile in absteigender Reihenfolge sortieren.
Meine Lösung
a = a[::, a[0,].argsort()[::-1]]
Wie funktioniert das also?
a[0,]
ist nur die erste Zeile, nach der ich sortieren möchte.
Jetzt benutze ich argsort, um die Reihenfolge der Indizes zu erhalten.
Ich verwende [::-1]
, weil ich eine absteigende Reihenfolge brauche.
Zuletzt benutze ich a[::, ...]
, um eine Ansicht mit den Spalten in der richtigen Reihenfolge zu erhalten.
[1]: https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors
Ein etwas komplizierteres lexsort
Beispiel - absteigend auf der 1. Spalte, sekundär aufsteigend auf der 2.
Die Tricks bei lexsort
sind, dass es nach Zeilen sortiert (daher das .T
), und der letzten den Vorrang gibt.
In [120]: b=np.array([[1,2,1],[3,1,2],[1,1,3],[2,3,4],[3,2,5],[2,1,6]])
In [121]: b
Out[121]:
array([[1, 2, 1],
[3, 1, 2],
[1, 1, 3],
[2, 3, 4],
[3, 2, 5],
[2, 1, 6]])
In [122]: b[np.lexsort(([1,-1]*b[:,[1,0]]).T)]
Out[122]:
array([[3, 1, 2],
[3, 2, 5],
[2, 1, 6],
[2, 3, 4],
[1, 1, 3],
[1, 2, 1]])
Hier ist eine weitere Lösung, die alle Spalten berücksichtigt (kompakterer Weg von [J.J][1]'s Antwort);
ar=np.array([[0, 0, 0, 1],
[1, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 1],
[0, 0, 1, 0],
[1, 1, 0, 0]])
Sortieren mit Lexsort,
ar[np.lexsort(([ar[:, i] for i in range(ar.shape[1]-1, -1, -1)]))]
Ausgabe:
array([[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0]])