2016-01-06 17 views
5

Supponiamo che io sono un set di dati come il seguenteUn modo migliore per aggregare i dati e mantenere i nomi di struttura di tabelle e colonne con i panda

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 

spesso mi voglio eseguire un'operazione groupby-aggregato dove ho gruppo da più colonne e applica più funzioni a una colonna. Inoltre, di solito non voglio una tabella multi-indexed a più livelli. Per fare ciò, mi stanno prendendo tre linee di codice che sembrano eccessive.

Per esempio

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

Esiste un modo migliore? Per non gripe, ma io vengo da un/sfondo R data.table dove qualcosa di simile a questo è un bel uno-liner come

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

si può evitare la 'reset_index' chiamando' groupby' con 'as_index = False' – maxymoo

+1

Sono d'accordo con te che il bias nei panda verso i multiindex è piuttosto fastidioso – maxymoo

risposta

2

si potrebbe usare @ risposta Happy01 ma invece di as_index=False si potrebbe aggiungere reset_index alla fine:

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, per reset_index funziona più velocemente:

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 

Si potrebbe fare lo stesso della soluzione, ma con una linea. Trasposizione tua dataframe poi non reset_index far cadere la colonna o livello 0 , poi trasporre indietro e fare reset_index di nuovo per ottenere l'output desiderato:

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 

Ma funziona più lentamente:

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

Nice writeup. Ma vedi il mio commento sotto la risposta di Happy. Anche questo metodo non generalizza bene, penso. – Ben

+1

Potresti fornire un esempio per quel caso? Perché penso all'ultimo livello di caduta del metodo, non solo colonna per nome: 'reset_index (level = 0, drop = True)' –

+0

Bingo. L'ultimo metodo (mentre è lento e abbastanza criptico) generalizza il meglio. – Ben

5

ne dite di questo:

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

Questo è bello. Si generalizza, dite se 'df' aveva un'altra colonna" x4 "per la quale volevo calcolare la media? Sono preoccupato che questa soluzione funzioni solo perché ho fornito un esempio troppo semplice che implica l'aggregazione su una colonna, ovvero x3. – Ben

+0

Sono d'accordo che funziona solo quando è coinvolta una sola colonna. Ma nel caso in cui abbiate anche bisogno, per esempio, di x4, allora potreste voler mantenere il livello della colonna (cioè, la loro media è per x3/x4). – Happy001

Problemi correlati