Mam Dataframe Pandy Pythona, w której kolumna zawiera nazwę miesiąca.
Jak mogę wykonać niestandardowe sortowanie za pomocą słownika, na przykład:
custom_dict = {'March':0, 'April':1, 'Dec':3}
Mam Dataframe Pandy Pythona, w której kolumna zawiera nazwę miesiąca.
Jak mogę wykonać niestandardowe sortowanie za pomocą słownika, na przykład:
custom_dict = {'March':0, 'April':1, 'Dec':3}
pd.Categoricaldomyślnie nie interpretuje kategorii w kolejności. Zobacz tę odpowiedź .
Odpowiedzi:
Pandy 0.15 wprowadziły serię kategorialną , która pozwala na znacznie jaśniejszy sposób:
Najpierw ustaw kolumnę miesiąca jako kategoryczną i określ kolejność, która ma być używana.
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
Teraz, kiedy posortujesz kolumnę miesiąca, zostanie ona posortowana według tej listy:
In [23]: df.sort_values("m")
Out[23]:
a b m
0 1 2 March
2 3 4 April
1 5 6 Dec
Uwaga: jeśli wartość nie znajduje się na liście, zostanie przekonwertowana na NaN.
Starsza odpowiedź dla zainteresowanych ...
Możesz stworzyć serię pośrednią i set_indexna tym:
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
Jak skomentowano, w nowszych pandach Series ma replacemetodę, aby zrobić to bardziej elegancko:
s = df['m'].replace({'March':0, 'April':1, 'Dec':3})
Niewielka różnica polega na tym, że nie wzrośnie, jeśli wartość znajduje się poza słownikiem (po prostu pozostanie taka sama).
s = df['m'].replace({'March':0, 'April':1, 'Dec':3})działa również dla linii 2 - tylko dla dobra każdego uczącego się pandy jak ja
.apply({'March':0, 'April':1, 'Dec':3}.get):) W 0.15 będziemy mieli Serie / kolumny kategorialne, więc najlepszym sposobem będzie użycie tego i wtedy sortowanie po prostu zadziała.
df.sort_values("m")w nowszych pandach (zamiast df.sort("m")), w przeciwnym razie otrzymasz AttributeError: 'DataFrame' object has no attribute 'sort';)
Wkrótce będziecie mogli korzystać sort_valuesz keyargumentu:
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
keyArgumentem bierze jako wejście serii i wraca serii. Ta seria jest wewnętrznie posortowana za pomocą argumentów, a posortowane indeksy są używane do zmiany kolejności wejściowej ramki DataFrame. Jeśli istnieje wiele kolumn do sortowania, funkcja klucza zostanie zastosowana do każdej z nich po kolei. Zobacz Sortowanie za pomocą kluczy .
Jedną z prostych metod jest użycie wyjścia Series.mapi Series.argsortindeksowanie do dfusing DataFrame.iloc(ponieważ argsort tworzy posortowane pozycje liczb całkowitych); ponieważ masz słownik; staje się to łatwe.
df.iloc[df['m'].map(custom_dict).argsort()]
a b m
0 1 2 March
2 3 4 April
1 5 6 Dec
Jeśli chcesz posortować w porządku malejącym , odwróć mapowanie.
df.iloc[(-df['m'].map(custom_dict)).argsort()]
a b m
1 5 6 Dec
2 3 4 April
0 1 2 March
Zwróć uwagę, że działa to tylko w przypadku elementów numerycznych. W przeciwnym razie będziesz musiał obejść ten problem, używając sort_valuesi uzyskując dostęp do indeksu:
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
Więcej opcji jest dostępnych z astype(jest to obecnie przestarzałe) lub pd.Categorical, ale musisz określić ordered=True, aby działało poprawnie .
# 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)
Teraz wystarczy prosty sort_valuestelefon:
df.sort_values('m')
a b m
0 1 2 March
2 3 4 April
1 5 6 Dec
Porządkowanie kategorialne będzie również uwzględniane podczas groupbysortowania wyników.
ordered=NoneDomyślnie ustawia kategorię Pandy . Jeśli nie zostanie ustawione, kolejność będzie błędna lub zepsuje się na V23. W szczególności funkcja Max daje błąd TypeError (kategoria nie jest uporządkowana dla operacji max).
Trochę późno w grze, ale oto sposób na utworzenie funkcji, która sortuje pandy Series, DataFrame i obiekty DataFrame z wieloma indeksami przy użyciu dowolnych funkcji.
Korzystam z df.iloc[index]metody, która odwołuje się do wiersza w Series / DataFrame według pozycji (w porównaniu z df.locodwołaniami według wartości). Używając tego, musimy po prostu mieć funkcję, która zwraca serię argumentów pozycyjnych:
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
Możesz użyć tego do tworzenia niestandardowych funkcji sortowania. Działa to na ramce danych użytej w odpowiedzi Andy'ego Haydena:
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
Działa to również w przypadku obiektów DataFrames i Series z wieloma indeksami:
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
Wydaje mi się, że jest to czyste, ale intensywnie wykorzystuje operacje w Pythonie, zamiast polegać na zoptymalizowanych operacjach pand. Nie wykonałem żadnych testów warunków skrajnych, ale wyobrażam sobie, że może to działać wolno na bardzo dużych ramkach DataFrame. Nie wiem, jak wypada porównanie wydajności z dodawaniem, sortowaniem, a następnie usuwaniem kolumny. Wszelkie wskazówki dotyczące przyspieszenia kodu będą mile widziane!
df.sort_index()do posortowania wszystkich poziomów indeksów.
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))
zwraca DataFrame z kolumnami March, April, Dec