2015-03-19 13 views
10

mam dataframe z Multiindex i chce zmodyfikować jeden konkretny poziom Multiindex. Na przykład, pierwszy poziom może być ciągi i mogą Chcę usunąć białe spacje z tego poziomu indeksu:Pandy Modyfikowanie określonego poziomu Multiindex

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

Jednakże powyższy kod powoduje błąd:

TypeError: 'FrozenList' does not support mutable operations. 

ja wiem można zresetować index i zmodyfikować kolumnę, a następnie ponownie utworzyć Multiindex, ale zastanawiam się, czy istnieje bardziej elegancki sposób na modyfikowanie jednego konkretnego poziomu Multiindex bezpośrednio.

+1

Nie, indeksy są niezmienne. Jeśli chcesz to zmienić, musisz go przerobić. – tnknepp

+1

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

Odpowiedz

10

Jak wspomniano w komentarzach, indeksy są niezmienne i musi być przerobiony podczas modyfikacji, ale nie trzeba używać reset_index o tym, można utworzyć nowy multi-indeks bezpośrednio:

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

Ten przykład jest dla 3-poziomowego indeksu, w którym chcesz zmodyfikować środkowy poziom. Musisz zmienić rozmiar krotki dla różnych rozmiarów.

1

Dzięki @ komentarzu cxrodgers męska, myślę, że najszybszym sposobem na to jest:

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

Stary, już odpowiedź:

okazało się, że lista zrozumienie sugeruje prac @Shovalt ale poczułem się wolny na moim komputerze (używając ramki danych z> 10 000 wierszy).

Zamiast tego, byłem w stanie wykorzystać .set_levels metodę, która była trochę szybciej dla mnie.

%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 

W rzeczywistości musiałem tylko dodać trochę tekstu. Było to nawet szybciej .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 

Rozwiązanie to opiera się na odpowiedzi w link z komentarzem @denfromufa ...

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

+0

Wydaje się to szybsze i bardziej eleganckie niż skonstruowanie nowego indeksu. Dodałbym również, że w większości przypadków wystarczy wpisać 'inplace = True'. – cxrodgers

+0

Właściwie myślę, że Twój kod zawiera błąd, powinno być 'df.index.levels [0]' 'gdziekolwiek masz df.index.get_level_values ​​(0)'. Tak też robią to w odpowiedzi, że łączysz – cxrodgers

+0

. Czy ".get_level_values" nie jest dla ciebie dostępna? Którą wersję pandy używasz? Jestem na v0.22.0 i oba wydają się dawać mi taki sam wynik, ale twoje zalecenie przy użyciu po prostu '.levels [0]' jest znacznie szybsze niż '.get_level_values ​​(0)'. Dodam to do mojej odpowiedzi. – John