2015-04-11 20 views
8

Ich habe ein Pandas DataFrame mit Indizes, die ich natürlich sortieren möchte. Natsort scheint nicht zu funktionieren. Das Sortieren der Indizes vor dem Erstellen des DataFrames scheint nicht hilfreich zu sein, da die Manipulationen, die ich mit dem DataFrame mache, die Sortierung im Prozess durcheinander bringen. Irgendwelche Gedanken darüber, wie ich die Indizes natürlich zurückverwandeln kann?Natürlich sortieren Pandas DataFrame

from natsort import natsorted 
import pandas as pd 

# An unsorted list of strings 
a = ['0hr', '128hr', '72hr', '48hr', '96hr'] 
# Sorted incorrectly 
b = sorted(a) 
# Naturally Sorted 
c = natsorted(a) 

# Use a as the index for a DataFrame 
df = pd.DataFrame(index=a) 
# Sorted Incorrectly 
df2 = df.sort() 
# Natsort doesn't seem to work 
df3 = natsorted(df) 

print(a) 
print(b) 
print(c) 
print(df.index) 
print(df2.index) 
print(df3.index) 
+0

@sethMMorton Ich vermutete, dass 'df3.index' dasselbe wie' c' ist, während die Daten sortiert werden, um sie inline mit ihren Indexwerten zu halten – agf1997

+0

Es wäre schön, wenn 'pd.sort' einen' Schlüssel hätte 'Option, aber es nicht. [Diese Antwort] (http://stackoverflow.com/a/27009771/1399279) bietet eine Problemumgehung, mit der Sie einen aus 'natsort_keygen' generierten Schlüssel übergeben können. – SethMMorton

+1

Ich habe gerade eine offizielle Anfrage an die 'Pandas' Devs gemacht,' Schlüssel' zu den 'sort' Methoden hier hinzuzufügen: https://github.com/pydata/pandas/issues/9855 – SethMMorton

Antwort

6

Wenn Sie die df sortieren, sortieren nur den Index oder die Daten und nicht direkt mit dem Index des df zuweisen als der Versuch, die df als arg übergeben wie eine leere Liste ergibt:

In [7]: 

df.index = natsorted(a) 
df.index 
Out[7]: 
Index(['0hr', '48hr', '72hr', '96hr', '128hr'], dtype='object') 

Beachten Sie, dass df.index = natsorted(df.index) funktioniert auch

, wenn Sie die df als arg es ergibt sich eine leere Liste, in diesem Fall passieren, weil die df leer ist (keine Spalten), sonst wird es die Spalten zurückgeben sortiert die ist nicht, was Sie wollen:

In [10]: 

natsorted(df) 
Out[10]: 
[] 

EDIT

Wenn Sie den Index sortiert werden sollen, so dass die Daten dann reindex zusammen mit dem Index neu geordnet verwenden:

In [13]: 

df=pd.DataFrame(index=a, data=np.arange(5)) 
df 
Out[13]: 
     0 
0hr 0 
128hr 1 
72hr 2 
48hr 3 
96hr 4 
In [14]: 

df = df*2 
df 
Out[14]: 
     0 
0hr 0 
128hr 2 
72hr 4 
48hr 6 
96hr 8 
In [15]: 

df.reindex(index=natsorted(df.index)) 
Out[15]: 
     0 
0hr 0 
48hr 6 
72hr 4 
96hr 8 
128hr 2 

Beachten Sie, dass das Ergebnis zuweisen reindex entweder zu einem neuen df oder zu sich selbst, es akzeptiert nicht die inplace param.

+0

Hallo, 'Natsort' Entwickler hier. 'natsort' hat derzeit keine explizite Unterstützung für die Verarbeitung ganzer Datenrahmenobjekte. Was wäre Ihre erwartete Ausgabe für die Übergabe eines Datenobjekts? – SethMMorton

+0

Ich glaube, das vermisst den Punkt. Mir ist klar, dass ich natürlich das a sortieren und das als Index verwenden kann, aber mein tatsächlicher Code vermasselt die Sortierung des Datenrahmenindex wegen der Manipulationen, die ich am Datenrahmen durchführe. Ich muss den Index und die zugehörigen Daten, während sie sich im Datenrahmen befinden, neu sortieren. – agf1997

+2

Also was fragen Sie hier, wollen Sie den Index nach Datenmanipulationen natsort? Sie können 'reindex' verwenden und' natsorted' auf dem Index 'df.reindex' (index = natsorted (df.index))' ' – EdChum

13

Die accepted answer beantwortet die Frage, die gestellt wird. Ich möchte auch hinzufügen, wie natsort auf Spalten in einem DataFrame zu verwenden, da dies die nächste Frage sein wird.

In [1]: from pandas import DataFrame 

In [2]: from natsort import natsorted, index_natsorted, order_by_index 

In [3]: df = DataFrame({'a': ['a5', 'a1', 'a10', 'a2', 'a12'], 'b': ['b1', 'b1', 'b2', 'b2', 'b1']}, index=['0hr', '128hr', '72hr', '48hr', '96hr']) 

In [4]: df 
Out[4]: 
     a b 
0hr  a5 b1 
128hr a1 b1 
72hr a10 b2 
48hr a2 b2 
96hr a12 b1 

Wie die accepted answer zeigt, durch den Sortier-Index ist recht einfach:

In [5]: df.reindex(index=natsorted(df.index)) 
Out[5]: 
     a b 
0hr  a5 b1 
48hr a2 b2 
72hr a10 b2 
96hr a12 b1 
128hr a1 b1 

Wenn Sie auf einer Säule in der gleichen Weise zu sortieren, können Sie den Index nach der Reihenfolge sortieren müssen, dass die gewünschte Säule wurde neu geordnet. natsort bietet die Komfortfunktionen index_natsorted und order_by_index, um genau das zu tun.

In [6]: df.reindex(index=order_by_index(df.index, index_natsorted(df.a))) 
Out[6]: 
     a b 
128hr a1 b1 
48hr a2 b2 
0hr  a5 b1 
72hr a10 b2 
96hr a12 b1 

In [7]: df.reindex(index=order_by_index(df.index, index_natsorted(df.b))) 
Out[7]: 
     a b 
0hr  a5 b1 
128hr a1 b1 
96hr a12 b1 
72hr a10 b2 
48hr a2 b2 

Wenn Sie mit einer beliebigen Anzahl von Spalten (oder einer Spalte und dem Index) neu anordnen möchten, können Sie zip (oder itertools.izip auf Python2) verwenden, um das Sortieren über mehrere Spalten angeben. Die erste Spalte gegeben wird die primäre Sortierspalte, dann sekundär sein, dann tertiär, etc ...

In [8]: df.reindex(index=order_by_index(df.index, index_natsorted(zip(df.b, df.a)))) 
Out[8]: 
     a b 
128hr a1 b1 
0hr  a5 b1 
96hr a12 b1 
48hr a2 b2 
72hr a10 b2 

In [9]: df.reindex(index=order_by_index(df.index, index_natsorted(zip(df.b, df.index)))) 
Out[9]: 
     a b 
0hr  a5 b1 
96hr a12 b1 
128hr a1 b1 
48hr a2 b2 
72hr a10 b2 

Hier ist eine alternative Methode unter Verwendung von Categorical Objekten, die ich von dem pandas devs gesagt worden ist "richtige" Art und Weise, dies zu tun. Dies erfordert (soweit ich das sehe) Pandas> = 0.16.0. Momentan funktioniert es nur für Spalten, aber scheinbar in Pandas> = 0.17.0 fügen sie CategoricalIndex hinzu, was es erlaubt, diese Methode für einen Index zu verwenden.

In [1]: from pandas import DataFrame 

In [2]: from natsort import natsorted 

In [3]: df = DataFrame({'a': ['a5', 'a1', 'a10', 'a2', 'a12'], 'b': ['b1', 'b1', 'b2', 'b2', 'b1']}, index=['0hr', '128hr', '72hr', '48hr', '96hr']) 

In [4]: df.a = df.a.astype('category') 

In [5]: df.a.cat.reorder_categories(natsorted(df.a), inplace=True, ordered=True) 

In [6]: df.b = df.b.astype('category') 

In [8]: df.b.cat.reorder_categories(natsorted(set(df.b)), inplace=True, ordered=True) 

In [9]: df.sort('a') 
Out[9]: 
     a b 
128hr a1 b1 
48hr a2 b2 
0hr  a5 b1 
72hr a10 b2 
96hr a12 b1 

In [10]: df.sort('b') 
Out[10]: 
     a b 
0hr  a5 b1 
128hr a1 b1 
96hr a12 b1 
72hr a10 b2 
48hr a2 b2 

In [11]: df.sort(['b', 'a']) 
Out[11]: 
     a b 
128hr a1 b1 
0hr  a5 b1 
96hr a12 b1 
48hr a2 b2 
72hr a10 b2 

Das Categorical Objekt können Sie eine Sortierreihenfolge für die DataFrame definieren zu verwenden.Die Elemente, die beim Aufruf von reorder_categories angegeben werden, müssen eindeutig sein, daher der Aufruf an set für die Spalte "b".

Ich überlasse es dem Benutzer zu entscheiden, ob dies besser ist als die reindex Methode oder nicht, da Sie die Spaltendaten unabhängig vor dem Sortieren innerhalb der DataFrame sortieren müssen (obwohl ich mir vorstellen, dass zweite Sortierung ist ziemlich effizient).


Volle Offenlegung, ich bin der natsort Autor.