2015-03-19 18 views
10

Ho un dataframe con Multiindex e vorrei modificare un particolare livello di Multiindex. Per esempio, il primo livello potrebbe essere stringhe e mi consiglia di rimuovere gli spazi bianchi da quel livello di indice:Panda: modifica di un particolare livello di Multiindex

df.index.levels[1] = [x.replace(' ', '') for x in df.index.levels[1]] 

Tuttavia, il codice sopra i risultati in un errore:

TypeError: 'FrozenList' does not support mutable operations. 

So può resettare_index e modificare la colonna e quindi ricreare il Multiindex, ma mi chiedo se c'è un modo più elegante per modificare direttamente un particolare livello del Multiindex.

+1

No, gli indici sono immutabili. Se vuoi cambiarlo devi rifarlo. – tnknepp

+1

http://stackoverflow.com/a/26629643/2230844 – denfromufa

risposta

10

Come accennato nei commenti, gli indici sono immutabili e deve essere rifatto quando si modifica, ma non c'è bisogno di utilizzare reset_index per questo, è possibile creare un nuovo multi-index direttamente:

df.index = pd.MultiIndex.from_tuples([(x[0], x[1].replace(' ', ''), x[2]) for x in df.index]) 

Questo esempio è per un indice a 3 livelli, in cui si desidera modificare il livello medio. È necessario modificare la dimensione della tupla per diversi livelli di dimensioni.

1

Grazie a @ commento di cxrodgers, penso che il modo più veloce per farlo è:

df.index = df.index.set_levels(df.index.levels[0].str.replace(' ', ''), level=0) 

Vecchio, la risposta più:

Ho trovato che la lista di comprensione suggerito dalle opere @Shovalt ma mi sentivo lento sulla mia macchina (usando un dataframe con> 10.000 righe).

Invece, sono stato in grado di utilizzare il metodo .set_levels, che è stato un po 'più veloce per me.

%timeit pd.MultiIndex.from_tuples([(x[0].replace(' ',''), x[1]) for x in df.index]) 
1 loop, best of 3: 394 ms per loop 

%timeit df.index.set_levels(df.index.get_level_values(0).str.replace(' ',''), level=0) 
10 loops, best of 3: 134 ms per loop 

In realtà, avevo solo bisogno di anteporre del testo. Questo era ancora più veloce con .set_levels:

%timeit pd.MultiIndex.from_tuples([('00'+x[0], x[1]) for x in df.index]) 
100 loops, best of 3: 5.18 ms per loop 

%timeit df.index.set_levels('00'+df.index.get_level_values(0), level=0) 
1000 loops, best of 3: 1.38 ms per loop 

%timeit df.index.set_levels('00'+df.index.levels[0], level=0) 
1000 loops, best of 3: 331 µs per loop 

Questa soluzione si basa sulla risposta nel collegamento dal commento di @denfromufa ...

python - Multiindex and timezone - Frozen list error - Stack Overflow

+0

Questo sembra più veloce e più elegante rispetto alla costruzione di un nuovo indice. Vorrei anche aggiungere che nella maggior parte dei casi dovresti semplicemente "inplace = True". – cxrodgers

+0

In realtà penso che il tuo codice contenga un errore, dovrebbe essere 'df.index.levels [0]' ovunque tu abbia 'df.index.get_level_values ​​(0)'. Questo è anche il modo in cui lo fanno nella risposta che colleghi – cxrodgers

+0

'.get_level_values' non è disponibile per te? Quale versione di panda stai usando? Sono su v0.22.0 ed entrambi sembrano darmi lo stesso risultato, ma la tua raccomandazione usando semplicemente '.levels [0]' è molto più veloce di '.get_level_values ​​(0)'. Lo aggiungerò alla mia risposta. – John