2016-05-09 13 views
7

Al momento ho un po 'di dati che è strutturato come segue:Pandas - Come raggruppare e disimpilare su più variabili?

data = {'participant': [100, 101, 102, 103, 104, 105, 106, 107, 108, 109], 
     'step_name': ['first', 'first', 'second', 'third', 'second', 'first', 'first', 'first', 'second', 'third'], 
     'title': ['acceptable', 'acceptable', 'not acceptable', 'acceptable', 'not acceptable', 'acceptable', 'not acceptable', 'acceptable', 'acceptable', 'acceptable'], 
     'colour': ['blue', 'blue', 'blue', 'green', 'green', 'blue', 'green', 'blue', 'blue', 'green'], 
     'class': ['A', 'B', 'B', 'A', 'B', 'A', 'A', 'A', 'A', 'B']} 
df = pd.DataFrame(data, columns=['participant', 'step_name', 'title', 'colour', 'class']) 

che si presenta come:

+----+---------------+-------------+----------------+----------+---------+ 
| | participant | step_name | title   | colour | class | 
|----+---------------+-------------+----------------+----------+---------| 
| 0 |   100 | first  | acceptable  | blue  | A  | 
| 1 |   101 | first  | acceptable  | blue  | B  | 
| 2 |   102 | second  | not acceptable | blue  | B  | 
| 3 |   103 | third  | acceptable  | green | A  | 
| 4 |   104 | second  | not acceptable | green | B  | 
| 5 |   105 | first  | acceptable  | blue  | A  | 
| 6 |   106 | first  | not acceptable | green | A  | 
| 7 |   107 | first  | acceptable  | blue  | A  | 
| 8 |   108 | second  | acceptable  | blue  | A  | 
| 9 |   109 | third  | acceptable  | green | B  | 
+----+---------------+-------------+----------------+----------+---------+ 

Ora voglio aggregare il set di dati in modo che ogni riga conta ciascuna delle variabili di ripetizione, che sono attualmente riuscito a fare insieme due variabili (step_name e title) come segue:

count_df = df[['participant', 'step_name', 'title']].groupby(['step_name', 'title']).count() 
count_df = count_df.unstack() 
count_df.fillna(0, inplace=True) 
count_df.columns = count_df.columns.get_level_values(1) 
count_df 

+--------+--------------+------------------+ 
|  | acceptable | not acceptable | 
|--------+--------------+------------------| 
| first |   4 |    1 | 
| second |   1 |    2 | 
| third |   2 |    0 | 
+--------+--------------+------------------+ 

Ora, però, mi piacerebbe avere un set aggiuntivo di colonne che includa i valori per le altre variabili (colour e class) - in pratica, voglio raggruppare e quindi disimpegnare su quelle variabili, ma non sono sicuro di come fare con più di 2 variabili. In definitiva, mi piacerebbe che il mio tavolo finale a guardare come questo:

+------+------+--------+--------------+------------------+ 
|class |colour| step | acceptable | not acceptable | 
|----------------------+--------------+------------------| 
| A | blue | first |   3 |    0 | 
| B | blue | first |   1 |    0 | 
| A |green | first |   0 |    1 | 
| B |green | first |   0 |    0 | 
| A | blue | second |   1 |    0 | 
| B | blue | second |   0 |    1 | 
| A |green | second |   0 |    0 | 
| B |green | second |   0 |    1 | 
| A |blue | third |   0 |    0 | 
| B |blue | third |   0 |    0 | 
| A |green | third |   1 |    0 | 
| B |green | third |   1 |    0 | 
+------+------+--------+--------------+------------------+ 

Come faccio a rimodellare i miei dati in modo che appaia come il mio ultimo esempio? Continuo a utilizzare le funzioni Unstack e Group?

risposta

5

Penso che avete bisogno pivot_table con aggfunc=len, reset_index e rename_axis (di nuovo in pandas0.18.0):

df = df.pivot_table(index=['class','colour','step_name'], 
        columns='title', 
        aggfunc=len, 
        values='participant', 
        fill_value=0).reset_index().rename_axis(None, axis=1) 
print df 
     class colour step_name acceptable not acceptable 
0   A blue  first   3    0 
1   A blue second   1    0 
2   A green  first   0    1 
3   A green  third   1    0 
4   B blue  first   1    0 
5   B blue second   0    1 
6   B green second   0    1 
7   B green  third   1    0 
+0

Grazie! Sembra che il bit "rename_axis' mi dà un errore, però -" TypeError: deve passare un indice per rinominare " – orange1

+1

È una nuova funzione in' pandas 0.18.0', puoi ometterlo. E usa 'df.columns.name = None' – jezrael

6

è possibile utilizzare pivot_table() per questo:

In [130]: df['count'] = 1 

In [134]: (df.pivot_table(index=['class','colour','step_name'], columns='title', 
    .....:     values='count', aggfunc='sum', fill_value=0) 
    .....: .reset_index() 
    .....:) 
Out[134]: 
title class colour step_name acceptable not acceptable 
0   A blue  first   3    0 
1   A blue second   1    0 
2   A green  first   0    1 
3   A green  third   1    0 
4   B blue  first   1    0 
5   B blue second   0    1 
6   B green second   0    1 
7   B green  third   1    0