2013-07-16 19 views
16

Ho il seguente pitone panda frame di dati:pitone panda groupby() risultato

df = pd.DataFrame({ 
    'A': [1,1,1,1,2,2,2,3,3,4,4,4], 
    'B': [5,5,6,7,5,6,6,7,7,6,7,7], 
    'C': [1,1,1,1,1,1,1,1,1,1,1,1] 
    }); 

df 
    A B C 
0 1 5 1 
1 1 5 1 
2 1 6 1 
3 1 7 1 
4 2 5 1 
5 2 6 1 
6 2 6 1 
7 3 7 1 
8 3 7 1 
9 4 6 1 
10 4 7 1 
11 4 7 1 

Vorrei avere un'altra colonna memorizzare un valore di una somma sui valori C per (entrambi) A fisso e B. Cioè, qualcosa di simile a:

A B C D 
0 1 5 1 2 
1 1 5 1 2 
2 1 6 1 1 
3 1 7 1 1 
4 2 5 1 1 
5 2 6 1 2 
6 2 6 1 2 
7 3 7 1 2 
8 3 7 1 2 
9 4 6 1 1 
10 4 7 1 2 
11 4 7 1 2 

ho provato con i panda groupby e che tipo di lavori:

res = {} 
for a, group_by_A in df.groupby('A'): 
    group_by_B = group_by_A.groupby('B', as_index = False) 
    res[a] = group_by_B['C'].sum() 

ma non so come ottenere i risultati da res in df nel modo ordinato. Sarei molto felice con qualsiasi consiglio su questo. Grazie.

risposta

13

Ecco un modo (anche se ritiene che questo dovrebbe funzionare in una volta con una domanda, non riesco a ottenerlo).

In [11]: g = df.groupby(['A', 'B']) 

In [12]: df1 = df.set_index(['A', 'B']) 

La funzione groupby size è quello che si desidera, dobbiamo corrispondere al 'A' e 'B' come l'indice:

In [13]: df1['D'] = g.size() # unfortunately this doesn't play nice with as_index=False 
# Same would work with g['C'].sum() 

In [14]: df1.reset_index() 
Out[14]: 
    A B C D 
0 1 5 1 2 
1 1 5 1 2 
2 1 6 1 1 
3 1 7 1 1 
4 2 5 1 1 
5 2 6 1 2 
6 2 6 1 2 
7 3 7 1 2 
8 3 7 1 2 
9 4 6 1 1 
10 4 7 1 2 
11 4 7 1 2 
+0

Grazie @Ady Hayden! La soluzione con 'sum' è più generica, penso. Infatti, non ho '1' in' C' (quando 'size' funziona perfettamente, come hai indicato nella tua soluzione), ma alcuni galleggiano, quindi per farlo funzionare correttamente ho bisogno di andare con' sum'. Ma comunque, brillante, grazie ancora. –

+4

Penso che il one-liner che stavi sognando fosse '' df ['D'] = df.groupby (['A', 'B']). Transform (np.size) ''. In tempi buoni e cattivi, c'è '' transform''. :-D –

6

Si potrebbe anche fare un uno di linea utilizzando fondersi come segue:

df = df.merge(pd.DataFrame({'D':df.groupby(['A', 'B'])['C'].size()}), left_on=['A', 'B'], right_index=True) 
+0

facile da leggere e capire – jiamo

5

Si potrebbe anche fare un uno di linea utilizzando transform applicata al groupby:

df['D'] = df.groupby(['A','B'])['C'].transform('sum')