2017-04-05 3 views
2

En supposant que je l'dataframe suivante:Python (Pandas) Ajouter sous-total sur chaque lvl de multiindice dataframe

a  b  c  Sce1  Sce2 Sce3 Sce4 Sce5 Sc6 
Animal Ground Dog 0.0  0.9  0.5  0.0  0.3  0.4 
Animal Ground Cat 0.6  0.5  0.3  0.5  1.0  0.2 
Animal Air  Eagle 1.0  0.1  0.1  0.6  0.9  0.1 
Animal Air  Owl 0.3  0.1  0.5  0.3  0.5  0.9  
Object Metal Car 0.3  0.3  0.8  0.6  0.5  0.6 
Object Metal Bike 0.5  0.1  0.4  0.7  0.4  0.2 
Object Wood Chair 0.9  0.6  0.1  0.9  0.2  0.8 
Object Wood Table 0.9  0.6  0.6  0.1  0.9  0.7 

Je veux créer un multiindice, qui contiendra la somme de chaque lvl. La sortie ressemblera à ceci:

a  b  c  Sce1 Sce2 Sce3 Sce4 Sce5 Sce6 
Animal    1.9  1.6  1.4  1.3  2.7  1.6 
     Ground  0.6  1.4  0.8  0.5  1.3  0.6 
       Dog 0.0  0.9  0.5  0.0  0.3  0.4 
       Cat 0.6  0.5  0.3  0.5  1.0  0.2 
     Air   1.3  0.2  0.7  0.8  1.4  1.0 
       Eagle 1.0  0.1  0.1  0.6  0.9  0.1 
       Owl 0.3  0.1  0.5  0.3  0.5  0.9 
Object    2.6  1.6  1.8  2.3  2.0  2.3 
     Metal  0.8  0.3  1.1  1.3  0.9  0.8 
       Car 0.3  0.3  0.8  0.6  0.5  0.6 
       Bike 0.5  0.1  0.4  0.7  0.4  0.2 
     Wood   1.8  1.3  0.6  1.0  1.1  1.5 
       Chair 0.9  0.6  0.1  0.9  0.2  0.8 
       Table 0.9  0.6  0.6  0.1  0.9  0.7 

En ce moment je suis en utilisant une boucle pour créer trois dataframes différents à chaque niveau, puis les manipuler sur Excel, comme ci-dessous. Je voulais donc prendre ce calcul en python si possible.

for i in range range(0,3): 
    df = df.groupby(list(df.columns)[0:lvl], as_index=False).sum() 
    return df 

Merci beaucoup à l'avance.

+0

Je pense qu'il n'y a pas de façon par défaut de le faire chez les pandas. Notez que vous pouvez produire les groupes incluant leurs sommes avec l'index multiniveau avec 'df.groupby (['a', 'b', 'c']). Sum()'. Cependant, il manque le total par groupe. Vous devriez regarder [cette question] (http://stackoverflow.com/questions/29413496/pandas-computing-total-sum-on-each-multiindex-sublevel) qui est très similaire à votre problème. –

Répondre

7

Avec une certaine utilisation libérale de MAGIC

pd.concat([ 
     df.assign(
      **{x: 'Total' for x in 'abc'[i:]} 
     ).groupby(list('abc')).sum() for i in range(4) 
    ]).sort_index() 

        Sce1 Sce2 Sce3 Sce4 Sce5 Sc6 
a  b  c          
Animal Air Eagle 1.0 0.1 0.1 0.6 0.9 0.1 
       Owl  0.3 0.1 0.5 0.3 0.5 0.9 
       Total 1.3 0.2 0.6 0.9 1.4 1.0 
     Ground Cat  0.6 0.5 0.3 0.5 1.0 0.2 
       Dog  0.0 0.9 0.5 0.0 0.3 0.4 
       Total 0.6 1.4 0.8 0.5 1.3 0.6 
     Total Total 1.9 1.6 1.4 1.4 2.7 1.6 
Object Metal Bike 0.5 0.1 0.4 0.7 0.4 0.2 
       Car  0.3 0.3 0.8 0.6 0.5 0.6 
       Total 0.8 0.4 1.2 1.3 0.9 0.8 
     Total Total 2.6 1.6 1.9 2.3 2.0 2.3 
     Wood Chair 0.9 0.6 0.1 0.9 0.2 0.8 
       Table 0.9 0.6 0.6 0.1 0.9 0.7 
       Total 1.8 1.2 0.7 1.0 1.1 1.5 
Total Total Total 4.5 3.2 3.3 3.7 4.7 3.9 

Je peux obtenir exactement ce que vous avez demandé avec

pd.concat([ 
     df.assign(
      **{x: '' for x in 'abc'[i:]} 
     ).groupby(list('abc')).sum() for i in range(1, 4) 
    ]).sort_index() 

        Sce1 Sce2 Sce3 Sce4 Sce5 Sc6 
a  b  c          
Animal    1.9 1.6 1.4 1.4 2.7 1.6 
     Air   1.3 0.2 0.6 0.9 1.4 1.0 
       Eagle 1.0 0.1 0.1 0.6 0.9 0.1 
       Owl  0.3 0.1 0.5 0.3 0.5 0.9 
     Ground   0.6 1.4 0.8 0.5 1.3 0.6 
       Cat  0.6 0.5 0.3 0.5 1.0 0.2 
       Dog  0.0 0.9 0.5 0.0 0.3 0.4 
Object    2.6 1.6 1.9 2.3 2.0 2.3 
     Metal   0.8 0.4 1.2 1.3 0.9 0.8 
       Bike 0.5 0.1 0.4 0.7 0.4 0.2 
       Car  0.3 0.3 0.8 0.6 0.5 0.6 
     Wood   1.8 1.2 0.7 1.0 1.1 1.5 
       Chair 0.9 0.6 0.1 0.9 0.2 0.8 
       Table 0.9 0.6 0.6 0.1 0.9 0.7 

Quant à la façon! Je vais laisser cela comme un exercice pour le lecteur.

+2

Brillant! @piRSquared –

+0

@ScottBoston Merci :-) – piRSquared

+0

Comment all_cols est-il défini? –

0

vous devez faire deux group by pour obtenir des sous-totaux à tous les niveaux d'agrégation. Ensuite, ajoutez-les à la DF initiale. Voici un related question.