Bedeutet eine Spalte einen Monatsnamen, dass es eine Spalte gibt, die Monatsnamen enthält (als meine Antwort), oder viele Spalten mit Spaltennamen als Monatsnamen (als Eumiros)?
Andy Hayden
1
Die akzeptierte Antwort ist veraltet und auch technisch falsch, da pd.Categoricaldie Kategorien nicht wie standardmäßig sortiert interpretiert werden. Siehe diese Antwort .
Machen Sie zuerst die Monatsspalte zu einer Kategorie und geben Sie die zu verwendende Reihenfolge an.
In [21]: df['m'] = pd.Categorical(df['m'], ["March", "April", "Dec"])
In [22]: df # looks the same!
Out[22]:
a b m
012 March
156 Dec
234 April
Wenn Sie nun die Monatsspalte sortieren, wird sie in Bezug auf diese Liste sortiert:
In [23]: df.sort_values("m")
Out[23]:
a b m
012 March
234 April
156 Dec
Hinweis: Wenn ein Wert nicht in der Liste enthalten ist, wird er in NaN konvertiert.
Eine ältere Antwort für Interessierte ...
Sie könnten eine Zwischenserie erstellen, und dazu set_index:
df = pd.DataFrame([[1, 2, 'March'],[5, 6, 'Dec'],[3, 4, 'April']], columns=['a','b','m'])
s = df['m'].apply(lambda x: {'March':0, 'April':1, 'Dec':3}[x])
s.sort_values()
In [4]: df.set_index(s.index).sort()
Out[4]:
a b m
012 March
134 April
256 Dec
Wie bereits erwähnt, hat Series bei neueren Pandas eine replaceMethode, um dies eleganter zu tun:
s = df['m'].replace({'March':0, 'April':1, 'Dec':3})
Der kleine Unterschied besteht darin, dass dies nicht erhöht wird, wenn es einen Wert außerhalb des Wörterbuchs gibt (er bleibt einfach gleich).
s = df['m'].replace({'March':0, 'April':1, 'Dec':3})funktioniert auch für Zeile 2 - nur für alle, die Pandas wie mich lernen
kdauria
@ Kdauria guter Ort! (Es ist schon eine Weile her, seit ich das geschrieben habe!) Ersetze definitiv die beste Option, eine andere ist die Verwendung .apply({'March':0, 'April':1, 'Dec':3}.get):) In 0.15 werden wir kategoriale Reihen / Spalten haben, also wird der beste Weg sein, das zu verwenden und dann zu sortieren wird einfach funktionieren.
Andy Hayden
@AndyHayden Ich habe mir erlaubt, die zweite Zeile durch die 'replace'-Methode zu ersetzen. Ich hoffe das ist ok
Faheem Mitha
@AndyHayden bearbeiten abgelehnt, aber ich denke immer noch, dass es eine vernünftige Änderung ist.
Faheem Mitha
7
Stellen Sie einfach sicher, dass Sie df.sort_values("m")in neueren Pandas (anstelle von df.sort("m")) verwenden, sonst erhalten Sie ein AttributeError: 'DataFrame' object has no attribute 'sort';)
Brainstorming
17
Pandas> = 1.1
Sie werden bald in der Lage sein, sort_valuesmit keyArgumenten zu verwenden:
pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'
custom_dict = {'March': 0, 'April': 1, 'Dec': 3}
df
a b m
012 March
156 Dec
234 April
df.sort_values(by=['m'], key=lambda x: x.map(custom_dict))
a b m
012 March
234 April
156 Dec
Das keyArgument nimmt eine Serie als Eingabe und gibt eine Serie zurück. Diese Reihe ist intern sortiert und die sortierten Indizes werden verwendet, um den eingegebenen DataFrame neu zu ordnen. Wenn mehrere Spalten sortiert werden müssen, wird die Schlüsselfunktion nacheinander auf jede Spalte angewendet. Siehe Sortieren mit Schlüsseln .
Pandas <= 1.0.X.
Eine einfache Methode besteht darin, die Ausgabe zu verwenden Series.mapund Series.argsortin dfusing zu indizieren DataFrame.iloc(da argsort sortierte ganzzahlige Positionen erzeugt). da du ein Wörterbuch hast; das wird einfach.
df.iloc[df['m'].map(custom_dict).argsort()]
a b m
012 March
234 April
156 Dec
Wenn Sie in absteigender Reihenfolge sortieren müssen , kehren Sie die Zuordnung um.
df.iloc[(-df['m'].map(custom_dict)).argsort()]
a b m
156 Dec
234 April
012 March
Beachten Sie, dass dies nur bei numerischen Elementen funktioniert. Andernfalls müssen Sie dies umgehen sort_valuesund auf den Index zugreifen:
df.loc[df['m'].map(custom_dict).sort_values(ascending=False).index]
a b m
156 Dec
234 April
012 March
Weitere Optionen sind verfügbar mit astype(dies ist jetzt veraltet) oder pd.Categorical, aber Sie müssen angeben, ordered=Truedamit es ordnungsgemäß funktioniert .
Sie haben es bereits betont, aber ich möchte es wiederholen, falls jemand anderes es überfliegt und verpasst: Pandas Kategoriesätze ordered=Nonestandardmäßig. Wenn nicht eingestellt, ist die Reihenfolge falsch oder bricht auf V23. Insbesondere die Max-Funktion gibt einen TypeError aus (Categorical ist für Operation max nicht geordnet).
Dave Liu
16
Ein bisschen spät im Spiel, aber hier ist eine Möglichkeit, eine Funktion zu erstellen, die Pandas Series-, DataFrame- und Multiindex-DataFrame-Objekte mit beliebigen Funktionen sortiert.
Ich benutze die df.iloc[index]Methode, die eine Zeile in einem Series / DataFrame nach Position referenziert (im Vergleich zu der df.loc, die nach Wert referenziert). Damit benötigen wir nur eine Funktion, die eine Reihe von Positionsargumenten zurückgibt:
defsort_pd(key=None,reverse=False,cmp=None):defsorter(series):
series_list = list(series)
return [series_list.index(i)
for i in sorted(series_list,key=key,reverse=reverse,cmp=cmp)]
return sorter
Hiermit können Sie benutzerdefinierte Sortierfunktionen erstellen. Dies funktioniert mit dem Datenrahmen, der in Andy Haydens Antwort verwendet wird:
df = pd.DataFrame([
[1, 2, 'March'],
[5, 6, 'Dec'],
[3, 4, 'April']],
columns=['a','b','m'])
custom_dict = {'March':0, 'April':1, 'Dec':3}
sort_by_custom_dict = sort_pd(key=custom_dict.get)
In [6]: df.iloc[sort_by_custom_dict(df['m'])]
Out[6]:
a b m
012 March
234 April
156 Dec
Dies funktioniert auch bei Multiindex-DataFrames- und Serienobjekten:
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
df = pd.DataFrame([
['New York','Mar',12714],
['New York','Apr',89238],
['Atlanta','Jan',8161],
['Atlanta','Sep',5885],
],columns=['location','month','sales']).set_index(['location','month'])
sort_by_month = sort_pd(key=months.index)
In [10]: df.iloc[sort_by_month(df.index.get_level_values('month'))]
Out[10]:
sales
location month
Atlanta Jan 8161
New York Mar 12714
Apr 89238
Atlanta Sep 5885
sort_by_last_digit = sort_pd(key=lambda x: x%10)
In [12]: pd.Series(list(df['sales'])).iloc[sort_by_last_digit(df['sales'])]
Out[12]:
2816101271435885189238
Für mich fühlt sich das sauber an, aber es verwendet Python-Operationen stark, anstatt sich auf optimierte Pandas-Operationen zu verlassen. Ich habe keine Stresstests durchgeführt, aber ich würde mir vorstellen, dass dies bei sehr großen DataFrames langsam werden könnte. Nicht sicher, wie die Leistung im Vergleich zum Hinzufügen, Sortieren und Löschen einer Spalte ist. Tipps zur Beschleunigung des Codes sind willkommen!
Würde dies zum Sortieren mehrerer Spalten / Indizes funktionieren?
ConanG
Ja, aber die ausgewählte Antwort ist ein weitaus besserer Weg, dies zu tun. Wenn Sie mehrere Indizes haben, ordnen Sie diese einfach in der von Ihnen bevorzugten Sortierreihenfolge an und sortieren Sie dann df.sort_index()alle Indexebenen.
Michael Delgado
9
import pandas as pd
custom_dict = {'March':0,'April':1,'Dec':3}
df = pd.DataFrame(...) # with columns April, March, Dec (probably alphabetically)
df = pd.DataFrame(df, columns=sorted(custom_dict, key=custom_dict.get))
Gibt einen DataFrame mit den Spalten März, April, Dezember zurück
pd.Categorical
die Kategorien nicht wie standardmäßig sortiert interpretiert werden. Siehe diese Antwort .Antworten:
Mit Pandas 0.15 wurde die kategoriale Serie eingeführt , mit der dies viel klarer möglich ist:
Machen Sie zuerst die Monatsspalte zu einer Kategorie und geben Sie die zu verwendende Reihenfolge an.
In [21]: df['m'] = pd.Categorical(df['m'], ["March", "April", "Dec"]) In [22]: df # looks the same! Out[22]: a b m 0 1 2 March 1 5 6 Dec 2 3 4 April
Wenn Sie nun die Monatsspalte sortieren, wird sie in Bezug auf diese Liste sortiert:
In [23]: df.sort_values("m") Out[23]: a b m 0 1 2 March 2 3 4 April 1 5 6 Dec
Hinweis: Wenn ein Wert nicht in der Liste enthalten ist, wird er in NaN konvertiert.
Eine ältere Antwort für Interessierte ...
Sie könnten eine Zwischenserie erstellen, und dazu
set_index
:df = pd.DataFrame([[1, 2, 'March'],[5, 6, 'Dec'],[3, 4, 'April']], columns=['a','b','m']) s = df['m'].apply(lambda x: {'March':0, 'April':1, 'Dec':3}[x]) s.sort_values() In [4]: df.set_index(s.index).sort() Out[4]: a b m 0 1 2 March 1 3 4 April 2 5 6 Dec
Wie bereits erwähnt, hat Series bei neueren Pandas eine
replace
Methode, um dies eleganter zu tun:s = df['m'].replace({'March':0, 'April':1, 'Dec':3})
Der kleine Unterschied besteht darin, dass dies nicht erhöht wird, wenn es einen Wert außerhalb des Wörterbuchs gibt (er bleibt einfach gleich).
quelle
s = df['m'].replace({'March':0, 'April':1, 'Dec':3})
funktioniert auch für Zeile 2 - nur für alle, die Pandas wie mich lernen.apply({'March':0, 'April':1, 'Dec':3}.get)
:) In 0.15 werden wir kategoriale Reihen / Spalten haben, also wird der beste Weg sein, das zu verwenden und dann zu sortieren wird einfach funktionieren.df.sort_values("m")
in neueren Pandas (anstelle vondf.sort("m")
) verwenden, sonst erhalten Sie einAttributeError: 'DataFrame' object has no attribute 'sort'
;)Pandas> = 1.1
Sie werden bald in der Lage sein,
sort_values
mitkey
Argumenten zu verwenden:pd.__version__ # '1.1.0.dev0+2004.g8d10bfb6f' custom_dict = {'March': 0, 'April': 1, 'Dec': 3} df a b m 0 1 2 March 1 5 6 Dec 2 3 4 April df.sort_values(by=['m'], key=lambda x: x.map(custom_dict)) a b m 0 1 2 March 2 3 4 April 1 5 6 Dec
Das
key
Argument nimmt eine Serie als Eingabe und gibt eine Serie zurück. Diese Reihe ist intern sortiert und die sortierten Indizes werden verwendet, um den eingegebenen DataFrame neu zu ordnen. Wenn mehrere Spalten sortiert werden müssen, wird die Schlüsselfunktion nacheinander auf jede Spalte angewendet. Siehe Sortieren mit Schlüsseln .Pandas <= 1.0.X.
Eine einfache Methode besteht darin, die Ausgabe zu verwenden
Series.map
undSeries.argsort
indf
using zu indizierenDataFrame.iloc
(da argsort sortierte ganzzahlige Positionen erzeugt). da du ein Wörterbuch hast; das wird einfach.df.iloc[df['m'].map(custom_dict).argsort()] a b m 0 1 2 March 2 3 4 April 1 5 6 Dec
Wenn Sie in absteigender Reihenfolge sortieren müssen , kehren Sie die Zuordnung um.
df.iloc[(-df['m'].map(custom_dict)).argsort()] a b m 1 5 6 Dec 2 3 4 April 0 1 2 March
Beachten Sie, dass dies nur bei numerischen Elementen funktioniert. Andernfalls müssen Sie dies umgehen
sort_values
und auf den Index zugreifen:df.loc[df['m'].map(custom_dict).sort_values(ascending=False).index] a b m 1 5 6 Dec 2 3 4 April 0 1 2 March
Weitere Optionen sind verfügbar mit
astype
(dies ist jetzt veraltet) oderpd.Categorical
, aber Sie müssen angeben,ordered=True
damit es ordnungsgemäß funktioniert .# Older version, # df['m'].astype('category', # categories=sorted(custom_dict, key=custom_dict.get), # ordered=True) df['m'] = pd.Categorical(df['m'], categories=sorted(custom_dict, key=custom_dict.get), ordered=True)
Jetzt reicht ein einfacher
sort_values
Anruf aus:df.sort_values('m') a b m 0 1 2 March 2 3 4 April 1 5 6 Dec
Die kategoriale Reihenfolge wird auch beim
groupby
Sortieren der Ausgabe berücksichtigt.quelle
ordered=None
standardmäßig. Wenn nicht eingestellt, ist die Reihenfolge falsch oder bricht auf V23. Insbesondere die Max-Funktion gibt einen TypeError aus (Categorical ist für Operation max nicht geordnet).Ein bisschen spät im Spiel, aber hier ist eine Möglichkeit, eine Funktion zu erstellen, die Pandas Series-, DataFrame- und Multiindex-DataFrame-Objekte mit beliebigen Funktionen sortiert.
Ich benutze die
df.iloc[index]
Methode, die eine Zeile in einem Series / DataFrame nach Position referenziert (im Vergleich zu derdf.loc
, die nach Wert referenziert). Damit benötigen wir nur eine Funktion, die eine Reihe von Positionsargumenten zurückgibt:def sort_pd(key=None,reverse=False,cmp=None): def sorter(series): series_list = list(series) return [series_list.index(i) for i in sorted(series_list,key=key,reverse=reverse,cmp=cmp)] return sorter
Hiermit können Sie benutzerdefinierte Sortierfunktionen erstellen. Dies funktioniert mit dem Datenrahmen, der in Andy Haydens Antwort verwendet wird:
df = pd.DataFrame([ [1, 2, 'March'], [5, 6, 'Dec'], [3, 4, 'April']], columns=['a','b','m']) custom_dict = {'March':0, 'April':1, 'Dec':3} sort_by_custom_dict = sort_pd(key=custom_dict.get) In [6]: df.iloc[sort_by_custom_dict(df['m'])] Out[6]: a b m 0 1 2 March 2 3 4 April 1 5 6 Dec
Dies funktioniert auch bei Multiindex-DataFrames- und Serienobjekten:
months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] df = pd.DataFrame([ ['New York','Mar',12714], ['New York','Apr',89238], ['Atlanta','Jan',8161], ['Atlanta','Sep',5885], ],columns=['location','month','sales']).set_index(['location','month']) sort_by_month = sort_pd(key=months.index) In [10]: df.iloc[sort_by_month(df.index.get_level_values('month'))] Out[10]: sales location month Atlanta Jan 8161 New York Mar 12714 Apr 89238 Atlanta Sep 5885 sort_by_last_digit = sort_pd(key=lambda x: x%10) In [12]: pd.Series(list(df['sales'])).iloc[sort_by_last_digit(df['sales'])] Out[12]: 2 8161 0 12714 3 5885 1 89238
Für mich fühlt sich das sauber an, aber es verwendet Python-Operationen stark, anstatt sich auf optimierte Pandas-Operationen zu verlassen. Ich habe keine Stresstests durchgeführt, aber ich würde mir vorstellen, dass dies bei sehr großen DataFrames langsam werden könnte. Nicht sicher, wie die Leistung im Vergleich zum Hinzufügen, Sortieren und Löschen einer Spalte ist. Tipps zur Beschleunigung des Codes sind willkommen!
quelle
df.sort_index()
alle Indexebenen.import pandas as pd custom_dict = {'March':0,'April':1,'Dec':3} df = pd.DataFrame(...) # with columns April, March, Dec (probably alphabetically) df = pd.DataFrame(df, columns=sorted(custom_dict, key=custom_dict.get))
Gibt einen DataFrame mit den Spalten März, April, Dezember zurück
quelle