2016-01-06 12 views
5

Angenommen, ich habe einen Datensatz wie folgenEine bessere Möglichkeit, Daten aggregieren und Tabellenstruktur und Spaltennamen mit Pandas

df = pd.DataFrame({'x1':['a','a','b','b'], 'x2':[True, True, True, False], 'x3':[1,1,1,1]}) 
df 
    x1  x2 x3 
0 a True 1 
1 a True 1 
2 b True 1 
3 b False 1 

Ich mag oft hält einen groupby-Aggregat Betrieb, wo ich Gruppe von mehreren Spalten durchzuführen und Wenden Sie mehrere Funktionen auf eine Spalte an. Außerdem möchte ich normalerweise keine multi-indexierte, mehrstufige Tabelle. Um dies zu erreichen, brauche ich drei Zeilen Code, die übertrieben erscheinen.

Zum Beispiel

bg = df.groupby(['x1', 'x2']).agg({'x3': {'my_sum':np.sum, 'my_mean':np.mean}}) 
bg.columns = bg.columns.droplevel(0) 
bg.reset_index() 

Gibt es einen besseren Weg? Nicht zu meckern, aber ich komme aus einem R/data.table Hintergrund, wo so etwas wie dieses ist eine nette Einzeiler wie

df[, list(my_sum=sum(x3), my_mean=mean(x3)), by=list(x1, x2)] 
+0

Sie das vermeiden können 'reset_index' durch Aufruf von' groupby' mit 'as_index = False' – maxymoo

+1

Ich stimme dir zu, dass die Voreingenommenheit in Pandas in Richtung multi-indexes ziemlich nervig ist – maxymoo

Antwort

2

Sie nutzen könnten @ Happy01 Antwort, aber statt as_index=False könnten Sie reset_index zum Ende hinzufügen:

In [1331]: df.groupby(['x1', 'x2'])['x3'].agg({'my_sum':np.sum, 'my_mean':np.mean}).reset_index() 
Out[1331]: 
    x1  x2 my_mean my_sum 
0 a True  1  2 
1 b False  1  1 
2 b True  1  1 

Benchmarking, für reset_index es funktioniert schneller:

In [1333]: %timeit df.groupby(['x1', 'x2'], as_index=False)['x3'].agg({'my_sum':np.sum, 'my_mean':np.mean}) 
100 loops, best of 3: 3.18 ms per loop 

In [1334]: %timeit df.groupby(['x1', 'x2'])['x3'].agg({'my_sum':np.sum, 'my_mean':np.mean}).reset_index() 
100 loops, best of 3: 2.82 ms per loop 

Sie könnten das gleiche wie Ihre Lösung, aber mit einer Linie. Transponieren Ihre Datenrahmen dann reset_index Sie Ihre Spalte oder Ebene 0, dann fallen die Umsetzung zurück und tun reset_index wieder Ihren gewünschten Ausgang zu erreichen:

In [1374]: df.groupby(['x1', 'x2']).agg({'x3': {'my_sum':np.sum, 'my_mean':np.mean}}).T.reset_index(level=0, drop=True).T.reset_index() 
Out[1374]: 
    x1  x2 my_mean my_sum 
0 a True  1  2 
1 b False  1  1 
2 b True  1  1 

Aber es funktioniert langsamer:

In [1375]: %timeit df.groupby(['x1', 'x2']).agg({'x3': {'my_sum':np.sum, 'my_mean':np.mean}}).T.reset_index(level=0, drop=True).T.reset_index() 
100 loops, best of 3: 5.13 ms per loop 
+0

Schöne write-up. Aber siehe meinen Kommentar unter Happy's Antwort. Diese Methode verallgemeinert sich auch nicht gut, denke ich. – Ben

+1

Können Sie ein Beispiel für diesen Fall angeben? Weil ich denke, letzte Methode Drop-Ebene, nicht nur Spalte nach Name: 'Reset_index (level = 0, drop = True)' –

+0

Bingo. Die letzte Methode (obwohl langsam und ziemlich kryptisch) verallgemeinert das Beste. – Ben

5

Wie wäre es damit:

In [81]: bg = df.groupby(['x1', 'x2'], as_index=False)['x3'].agg({'my_sum':np.sum, 'my_mean':np.mean}) 

In [82]: print bg 
    x1  x2 my_sum my_mean 
0 a True  2  1 
1 b False  1  1 
2 b True  1  1 
+0

Das ist nett. Verallgemeinert es, ob "df" eine andere Spalte "x4" hatte, für die ich den Mittelwert berechnen wollte? Ich mache mir Sorgen, dass diese Lösung nur funktioniert, weil ich ein übermäßig einfaches Beispiel gegeben habe, das die Aggregation in einer Spalte beinhaltet, nämlich x3. – Ben

+0

Ich stimme zu, dass dies nur funktioniert, wenn nur eine Spalte beteiligt ist. Aber in dem Fall, dass Sie auch, sagen wir, Mittelwert von x4 benötigen, dann möchten Sie vielleicht die Spaltenebene behalten (d. H., Sie bedeuten für x3/x4). – Happy001

Verwandte Themen