2016-05-17 12 views
0

Ich habe einen multi-indizierten Pandas Datenrahmen von numerischen Werten. Ich möchte jede Zeile in einer Teilmenge des Datenrahmens sequentiell sortieren, indem ich zwei andere Teilmengen der Daten verwende. Ich glaube, das folgende Beispiel wäre besser veranschaulichen, was ich brauche:Sequenzielles Sortieren in multi-indizierten Pandas DataFrame

Betrachten Sie dieses Beispiel Datensatz:

      A   B   C   D 
rtr 2015-01-31 -1.085631 -0.204201 1.730024 1.710438 
    2015-02-28 0.997345 1.979348 1.232650 -0.056341 
key1 2015-01-31 6.180000 0.990000 2.440000 1.920000 
    2015-02-28 1.140000 1.810000 4.560000 0.740000 
key2 2015-01-31 86.000000 36.000000 61.000000 34.000000 
    2015-02-28 97.000000 96.000000 48.000000 98.000000 

Betrachten wir die letzten Zeilen von key1, key2 und rtr unter dem Datum 2015-02-28:

  1. In df.loc['key1'], erhalten Sie die Spaltennamen der 2 größten Werte. (dh: C, B)
  2. schließen Sie die Spalten C und B aus dem Spaltenbereich aus. (dh: verbleibende Spalten: A, D)
  3. in df.loc['key2'], den Spaltennamen des größten Werts im verbleibenden Spaltenbereich abrufen. (Das heißt: die Werte in den Spalten A und D, D größer -> Rückkehr D)
  4. fetch Werte von df.loc['rtr'] entsprach, die in den Schritten 1 und 3 (dh gefunden zu den Spaltennamen entsprechen: Liefern Werte df.loc['rtr'].loc['20150228',['C','B','D']]
In [140]: df.loc['rtr'].loc['20150228',['C','B','D']] 
Out[140]: 
C 1.232650 
B 1.979348 
D -0.056341 
Name: 2015-02-28 00:00:00, dtype: float64 

-Code zum Beispiel Datengenerierung:

## generate data: 
d1,d2,d3 = {},{},{} 
np.random.seed(123) 
for col in list("ABCD"): 
    d1[col] = np.random.randn(2) 
    d2[col] = np.random.gamma(2,3,2).round(2) 
    d3[col] = np.random.random_integers(0,100, 2) 
t_index = pd.date_range(start = '2015-01-31', periods = 2, freq = "M") 

dat1 = pd.DataFrame(d1, index = t_index) 
dat2 = pd.DataFrame(d2, index = t_index) 
dat3 = pd.DataFrame(d3, index = t_index) 

df = pd.concat([dat1, dat2, dat3], keys = ['rtr', 'key1', 'key2']) 
+0

Es ist immer noch nicht klar, was Sie wollen. – piRSquared

+0

Hallo Kumpel, könntest du klären, welcher Teil unklar ist? –

+1

Sie haben Sternchen auf Beispieldaten nur für "2015-01-31" angewendet. Es wäre hilfreich, ein besseres Verständnis dafür zu erhalten, wie die erwartete Ausgabe aussehen wird. Wenn ich Fragen sehe, die beantwortet werden müssen, mache ich einen Urteilsspruch, wie lange es dauert, bis ich die Frage beantworte. Ich vergleiche das mit meiner aktuellen Arbeitsbelastung. Schließlich, wenn meine Augen glasig werden, wenn ich die Frage lese, überspringe ich sie. Es ist in Ihrem besten Interesse, es so einfach wie möglich für jemanden zu machen, zu lesen und zu verstehen. – piRSquared

Antwort

1

Schritt 1: Lösen Sie das Problem für ein bestimmtes Datum.

df1 = df.xs('2015-01-31', level=1) 

columns = df1.loc['key1'].nlargest(2).index.tolist() 
columns.append(df1.loc['key2'][df.columns.difference(columns)].idxmax()) 
df1.loc['rtr', columns] 

Wir verwenden nlargest und den Index des Ergebnisses, weil idxmax nur für eine maximale funktioniert. Wir verwenden idxmax in der folgenden Zeile, nach dem Ausschluss der vorherigen Spalten mit Pandas Index difference Methode.

Schritt 2: Verwenden Sie groupby, um die obige Lösung für jedes Datum einzeln anzuwenden.

def func(df2): 
    df1 = df2.reset_index(level=1, drop=True) 
    columns = df1.loc['key1'].nlargest(2).index.tolist() 
    columns.append(df1.loc['key2'][df.columns.difference(columns)].idxmax()) 
    return df1.loc['rtr', columns] 

df.groupby(level=1).apply(func) 

Die reset_index wird hinzugefügt, da im Gegensatz zu xs, hat groupby nicht den Indexstand fallen.

+1

Ausgezeichnete Lösung! Ich werde wahrscheinlich auch im zweiten Schritt die Verwendung von 'nlargest (m) .index.tolist()' auflösen, da dies auf einen viel größeren Datensatz und mehrere Auswahlen für jeden Schlüssel verallgemeinert werden soll. Ich hätte nie gedacht, 'groupby' zu verwenden, da ich stattdessen mit' np.argsort' und 'df.apply' gekämpft habe. Danke für den Code! –