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 die Zeilen nach der zweiten Spalte sortieren, sodass ich zurückkomme:
array([[7, 0, 5],
[9, 2, 3],
[4, 5, 6]])
@steve 's ist eigentlich die eleganteste Art und Weise, dies zu tun.
Für den "richtigen" Weg sehen Sie das Argument für die Reihenfolge von numpy.ndarray.sort .
Sie müssen Ihr Array jedoch als Array mit Feldern (strukturiertes Array) anzeigen.
Der "richtige" Weg ist ziemlich hässlich, wenn Sie Ihr Array anfangs nicht mit Feldern definiert haben ...
Um es kurz 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 es vor Ort 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, so weit ich weiß ...
Der einzige Vorteil dieser Methode besteht darin, dass das Argument "Reihenfolge" eine Liste der Felder ist, nach denen die Suche sortiert werden soll. Sie können beispielsweise nach der zweiten Spalte, dann nach der dritten Spalte und dann nach der ersten Spalte sortieren, indem Sie order = ['f1', 'f2', 'f0'] angeben.
Ich nehme an, das funktioniert: a[a[:,1].argsort()]
Dies zeigt die zweite Spalte von a
an und sortiert sie entsprechend.
Sie können nach Steve Tjoas Methode nach mehreren Spalten sortieren, indem Sie eine stabile Sortierung wie Mergesort verwenden und die Indizes von den niedrigstwertigen zu den höchstwertigen 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')]
Dies wird nach Spalte 0, dann 1 und 2 sortiert.
Aus dem Python-Dokumentations-Wiki , ich denke, Sie können Folgendes 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]]]
Von der NumPy-Mailingliste , hier eine andere 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]])
Für den Fall, dass jemand die Sortierung in einem kritischen Teil ihrer Programme verwenden möchte, folgt 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 wäre die Indexierung mit argsort die bisher schnellste Methode ...
Ich hatte ein ähnliches Problem.
Mein Problem:
Ich möchte eine SVD berechnen und muss meine Eigenwerte in absteigender Reihenfolge sortieren. Ich möchte aber die Abbildung zwischen Eigenwerten und Eigenvektoren beibehalten. Meine Eigenwerte waren in der ersten Zeile und der entsprechende Eigenvektor in derselben 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?
a[0,]
ist nur die erste Zeile, nach der ich sortieren möchte.
Jetzt benutze ich argsort, um die Reihenfolge der Indizes zu ermitteln.
Ich benutze [::-1]
, weil ich eine absteigende Reihenfolge brauche.
Schließlich benutze ich a[::, ...]
, um eine Ansicht mit den Spalten in der richtigen Reihenfolge zu erhalten.
Ein etwas komplizierteres lexsort
-Beispiel - absteigend in der 1. Spalte, sekundär aufsteigend in der 2. Spalte. Die Tricks mit lexsort
sind so, dass sie nach Zeilen sortiert werden (daher der .T
) und der letzten Priorität geben.
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 andere Lösung, die alle Spalten berücksichtigt (kompaktere Art der Antwort von J.J );
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]])
Sortiere 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]])