2014-06-18 46 views
9

Ho un dataframe, grouped, con colonne multiindex come qui sotto:Pandas dataframe con colonna multiindex - merge livelli

import pandas as pd 
codes = ["one","two","three"]; 
colours = ["black", "white"]; 
textures = ["soft", "hard"]; 
N= 100 # length of the dataframe 
df = pd.DataFrame({ 'id' : range(1,N+1), 
        'weeks_elapsed' : [random.choice(range(1,25)) for i in range(1,N+1)], 
        'code' : [random.choice(codes) for i in range(1,N+1)], 
        'colour': [random.choice(colours) for i in range(1,N+1)], 
        'texture': [random.choice(textures) for i in range(1,N+1)], 
        'size': [random.randint(1,100) for i in range(1,N+1)], 
        'scaled_size': [random.randint(100,1000) for i in range(1,N+1)] 
        }, columns= ['id', 'weeks_elapsed', 'code','colour', 'texture', 'size', 'scaled_size']) 
grouped = df.groupby(['code', 'colour']).agg({'size': [np.sum, np.average, np.size, pd.Series.idxmax],'scaled_size': [np.sum, np.average, np.size, pd.Series.idxmax]}).reset_index() 

>> grouped 
    code colour  size       scaled_size       
        sum average size idxmax   sum average size idxmax 
0 one black 1031 60.647059 17  81  185.153944 10.891408 17  47 
1 one white  481 37.000000 13  53  204.139249 15.703019 13  53 
2 three black  822 48.352941 17  6  123.269405 7.251141 17  31 
3 three white 1614 57.642857 28  50  285.638337 10.201369 28  37 
4 two black  523 58.111111  9  85  80.908912 8.989879  9  88 
5 two white  669 41.812500 16  78  82.098870 5.131179 16  78 
[6 rows x 10 columns] 

Come posso appiattire/unire i livelli dell'indice colonna come: "Livello 1 | Livello 2", per esempio size|sum, scaled_size|sum. eccetera? Se questo non è possibile, c'è un modo per groupby() come ho fatto in precedenza senza creare colonne con più indici?

risposta

6

Si può sempre modificare le colonne:

grouped.columns = ['%s%s' % (a, '|%s' % b if b else '') for a, b in grouped.columns] 
+1

se una delle colonne nel livello 1 è uguale a' 0', quindi l'espressione sopra la ignorerà qui: 'b se b else '' '. Invece, ho usato 'b! = ''', Quindi 'grouped.columns = ['% s% s'% (a, '|% s'% b if b! = '' Else '') per a, b in grouped.columns] '. Questo potrebbe essere utile dopo aver usato 'groupby' che enumera colonne con numeri a partire da 0. –

+1

ci sarebbe un problema con' None's in quello, quindi dovresti fare 'if (b == 0 ob)' , ma ancora una buona chiamata – acushner

+0

@acusher, hai ragione, anche se 'se b non è None' dovrebbe il modo semplice di esprimerlo ... –

0

Io non sono sicuro se ho capito cosa vuoi dire;) ma si poteva combinare due colonne con dati stringa in Indice del genere:

df['merged_ix'] = df.code + '|' + df.colour 
df.set_index(df.merged_ix, inplace=True) 
+0

Grazie, ma non è quello che sto chiedendo . Ho modificato la domanda per renderla più chiara. Voglio sbarazzarmi dei due livelli nei nomi delle colonne. Se ci sono due livelli, ni vuoi unirli in uno, come 'size | sum' – Rhubarb

9

Esiste un potenziale un modo migliore, un modo più pigro per appiattire le colonne multiindex.

grouped.columns = grouped.columns.map('|'.join) 

print(grouped) 

uscita:

code| colour| size|sum size|average size|size size|idxmax \ 
0 one black  862  53.875000   16   14 
1 one white  554  46.166667   12   18 
2 three black  842  49.529412   17   90 
3 three white  740  56.923077   13   97 
4 two black  1541  61.640000   25   50 

    scaled_size|sum scaled_size|average scaled_size|size scaled_size|idxmax 
0    6980   436.250000    16     77 
1    6101   508.416667    12     13 
2    7889   464.058824    17     64 
3    6329   486.846154    13     73 
4   12809   512.360000    25     23 

Modifica a portata di mano colonne numeriche utilizzano:

grouped.columns = grouped.columns.map('{0[0]}|{0[1]}'.format) 

uscita:

code| colour| size|sum size|average size|size size|idxmax \ 
0 one black  734  52.428571   14   30 
1 one white  1110  65.294118   17   88 
2 three black  930  51.666667   18   3 
3 three white  1140  51.818182   22   20 
4 two black  656  38.588235   17   77 
5 two white  704  58.666667   12   17 

    scaled_size|sum scaled_size|average scaled_size|size scaled_size|idxmax 
0    8229   587.785714    14     57 
1    8781   516.529412    17     73 
2   10743   596.833333    18     21 
3   10240   465.454545    22     26 
4    9982   587.176471    17     16 
5    6537   544.750000    12     49 
+0

non funziona quando hai colonne numeriche ' MultiIndex (levels = [ [u'col_a ', u'col_b', u'col_c '], [7950230.0, 12304568.0]], etichette = [[0, 0, 1], [0, 1, 1]], nomi = [lev , sublev ']) ' restituisce ' TypeError: sequenza articolo 1: stringa attesa, float found' –

+0

@PabloA grouped.columns.map (' {0 [0]} | {0 [1]} '. format) –

+1

Ottima soluzione. Pythonic e flessibile. – Kevin

Problemi correlati