2015-03-19 1 views
10

У меня есть DataFrame с Multiindex и хотел бы изменить один конкретный уровень Multiindex. Например, первый уровень может быть строками и я могу хотеть, чтобы удалить пробелы из этого индекса уровня:Pandas: Изменить определенный уровень Multiindex

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

Однако приведенный выше код приводит к ошибке:

TypeError: 'FrozenList' does not support mutable operations. 

Я знаю, что я может reset_index и изменить столбец, а затем повторно создать Multiindex, но я задаюсь вопросом, есть ли более элегантный способ изменить один конкретный уровень Multiindex напрямую.

+1

Неа, индексы неизменны. Если вы хотите изменить его, вы должны переделать его. – tnknepp

+1

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

ответ

10

Как уже упоминалось в комментариях, индексы неизменны и должны быть переделаны при изменении, но вы не должны использовать reset_index для этого, вы можете создать новый мультииндекс непосредственно:

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

Этот пример для 3-уровневого индекса, где вы хотите изменить средний уровень. Вам нужно изменить размер кортежа для разных уровней.

1

Благодаря @ комментарий cxrodgers, я думаю, что самый быстрый способ сделать это:

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

Старый, развернутый ответ:

Я обнаружил, что список понимание предложил @Shovalt работ но чувствовал себя медленным на моей машине (используя фрейм данных с> 10 000 строк).

Вместо этого я смог использовать метод .set_levels, который был для меня довольно быстрым.

%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 

На самом деле, мне просто нужно было добавить текст. Это было еще быстрее .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 

Это решение основано на ответ в связи с замечанием @denfromufa ...

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

+0

Это кажется более быстрым и более элегантным, чем создание нового индекса. Я бы также добавил, что в большинстве случаев вы просто делаете 'inplace = True'. – cxrodgers

+0

На самом деле, я думаю, что ваш код содержит ошибку, он должен быть 'df.index.levels [0]' где бы вы ни были 'df.index.get_level_values ​​(0)'. Это также то, как они делают это в ответе, который вы связываете – cxrodgers

+0

. '' '.get_level_values' недоступен для вас? Какую версию панд вы используете? Я на v0.22.0, и оба, похоже, дают мне тот же результат, но ваша рекомендация с использованием просто .levels [0] 'намного быстрее, чем' .get_level_values ​​(0) '. Я добавлю это к своему ответу. – John

 Смежные вопросы

  • Нет связанных вопросов^_^