2017-07-20 1 views
2

Ich habe ein MultiIndex pandas DataFrame nach dem Aufruf groupby, und müssen es in einer Art und Weise glätten similar to flattening a pivot table. Der Großteil der Analyse ist bereits um das gruppierte Objekt herum aufgebaut und würde daher nicht in eine Pivot-Tabelle umgeformt werden müssen.Flachen Pandas DataFrame ohne Pivot-Tabelle

Betrachten wir einige Blinddaten,

dummy_data = pd.DataFrame({'Ccy' : ['EUR', 'EUR', 'CAD', 'CAD', 'EUR', 'EUR', 'CAD', 'EUR'], 
        'Venue' : ['BAML']*5 + ['BARX']*3, 
        'Price': np.abs(np.random.randn(8)), 
        'volume': np.abs(10*np.random.randn(8)) 
        }, 
        index = pd.date_range('7/19/2017', periods=8)) 

dummy_data.index.name = "datetime" 
print dummy_data 


>>>   Ccy  Price Venue  volume 
datetime         
2017-07-19 EUR 1.338521 BAML 11.227553 
2017-07-20 EUR 0.882715 BAML 0.307711 
2017-07-21 CAD 0.977815 BAML 14.196170 
2017-07-22 CAD 1.262272 BAML 0.055213 
2017-07-23 EUR 0.752433 BAML 5.315777 
2017-07-24 EUR 0.699008 BARX 2.299045 
2017-07-25 CAD 1.625567 BARX 6.474822 
2017-07-26 EUR 2.122562 BARX 5.026135 

Ziel zu Gruppendaten von Ccy und Venue, gelten ein filter Betrieb jeder Untergruppe, und dann die Gruppen in das Format dieses ursprünglichen Rahmen abzuflachen zurück. Betrachten wir einen einfachen Filter, Zeilen behält wo price > 0.8

dummy_data.groupby(['Ccy', 'Venue']).apply(lambda x: x[x['Price'] > 0.8]) 

>>>      Ccy  Price Venue  volume 
Ccy Venue datetime         
CAD BAML 2017-07-21 CAD 0.977815 BAML 14.196170 
      2017-07-22 CAD 1.262272 BAML 0.055213 
    BARX 2017-07-25 CAD 1.625567 BARX 6.474822 
EUR BAML 2017-07-19 EUR 1.338521 BAML 11.227553 
      2017-07-20 EUR 0.882715 BAML 0.307711 
    BARX 2017-07-26 EUR 2.122562 BARX 5.026135 

Alles, was ich jetzt brauchen, ist zu fill-in/abflachen die Ccy und Venue Spalten, so dass

Ccy Venue datetime         
CAD BAML 2017-07-21 ...      CAD BAML 2017-07-21 ... 
      2017-07-22 ...      CAD BAML 2017-07-22 ... 
    BARX 2017-07-25 ... ---> BECOMES ---> CAD BARX 2017-07-25 ... 
EUR BAML 2017-07-19 ...      EUR BAML 2017-07-19 ... 
      2017-07-20 ...      EUR BAML 2017-07-20 ... 

Ich muss dies tun, weil wir haben eine Reihe von Zeichenprogrammen, die nicht flexibel genug sind, um gruppierte Daten zu verarbeiten. Sollte es keine ungroup() oder flatten() Methode geben, die reziprok zu der groupby() Operation ist?

Hinweis: der triviale Filter in diesem Beispiel hätte auf die nicht gruppierten Daten angewendet werden können. In Wirklichkeit ist mein Filter komplexer und macht nur bei Untergruppen Sinn.


Lösungsversuche (Versuche 1 und 2 von pivot table solution)

Attempt 1: melt Verfahren verliert den datetime Index.

print dummy_data.groupby(['Ccy', 'Venue']).apply(lambda x: x[x['Price'] > 0.8]).melt() 

>>> variable  value 
0  Ccy  CAD 
1  Ccy  CAD 
2  Ccy  CAD 
3  Ccy  EUR 
4  Ccy  EUR 
5  Ccy  EUR 
6  Price 0.977815 
7  Price 1.26227 
8  Price 1.62557 
9  Price 1.33852 

Versuch 2: die accepted answer führt zu einer KeyError

dummy_data.groupby(['Ccy', 'Venue']).apply(lambda x: x[x['Price'] > 0.8]).unstack().reset_index().drop('level_0', axis=1) 

KeyError: 'level_0'

Versuch 3:reset_index() führt zu Valueerror

dummy_data.groupby(['Ccy', 'Venue']).apply(lambda x: x[x['Price'] > 0.8]).reset_index() 

ValueError: cannot insert Venue, already exists

Versuch 4:as_index=False (ohne group_keys Stichwort)

out = dummy_data.groupby(['Ccy', 'Venue'], as_index=False).apply(lambda x: x[x['Price'] > 0.8]) 
print out 
print out.index 

       Ccy  Price Venue  volume 
    datetime         
0 2017-07-21 CAD 0.977815 BAML 14.196170 
    2017-07-22 CAD 1.262272 BAML 0.055213 
1 2017-07-25 CAD 1.625567 BARX 6.474822 
2 2017-07-19 EUR 1.338521 BAML 11.227553 
    2017-07-20 EUR 0.882715 BAML 0.307711 
3 2017-07-26 EUR 2.122562 BARX 5.026135 
MultiIndex(levels=[[0, 1, 2, 3], [2017-07-19 00:00:00, 2017-07-20 00:00:00, 2017-07-21 00:00:00, 2017-07-22 00:00:00, 2017-07-25 00:00:00, 2017-07-26 00:00:00]], 
      labels=[[0, 0, 1, 2, 2, 3], [2, 3, 4, 0, 1, 5]], 
      names=[None, u'datetime']) 

Das bekommt mir sehr nahe, aber das Objekt ist immer noch MultiIndexed. Wie können wir nur den Datetime-Index zurückbekommen?

+0

Ich glaube, Sie reset_index nach Pivot – piRSquared

+0

Check out Versuch 3 in meine Frage aktualisiert –

Antwort

2

Dies kann sein, was Sie wollen:

dummy_data.groupby(['Ccy', 'Venue'], group_keys=False)\ 
      .apply(lambda x: x[x['Price'] > 0.8]) 
+0

Ahh Slick danken Sie benötigen.War mir dieses magischen Schlüsselwort nicht bewusst. Gibt es einen Grund, warum diese Lösung dem Vorschlag von COLDSPEED vorzuziehen ist? Beide machen mehr oder weniger dasselbe. Können Sie aktualisieren, um den. Apply() Filter nur für die Vollständigkeit zu haben –

+0

@AdamHughes Geschwindigkeit ... diese Lösung ist ein paar Ticks schneller, weil der Index inhärent gelöscht wird. –

+0

Ok, ich werde dies als akzeptierte Antwort für die (vermutete) Geschwindigkeitserhöhung und den Gewinn des Code-Golfs markieren. Schätze beide Lösungen –