Pandas: изменение определенного уровня Multiindex
У меня есть dataframe с Multiindex и хотел бы изменить один конкретный уровень Multiindex. Например, первый уровень может быть строками, и я могу удалить белые пробелы с этого уровня индекса:
df.index.levels[1] = [x.replace(' ', '') for x in df.index.levels[1]]
Однако приведенный выше код приводит к ошибке:
TypeError: 'FrozenList' does not support mutable operations.
Я знаю, что могу сбросить_индекс и изменить столбец, а затем повторно создать Multiindex, но мне интересно, есть ли более элегантный способ изменить один конкретный уровень Multiindex напрямую.
Ответы
Ответ 1
Как указано в комментариях, индексы неизменяемы и должны быть переделаны при модификации, но для этого вам не нужно использовать reset_index
, вы можете создать новый мультииндекс напрямую:
df.index = pd.MultiIndex.from_tuples([(x[0], x[1].replace(' ', ''), x[2]) for x in df.index])
Этот пример предназначен для 3-уровневого индекса, где вы хотите изменить средний уровень. Вам нужно изменить размер кортежа для разных уровней.
Ответ 2
Благодаря комментарию @cxrodgers, я думаю, что самый быстрый способ сделать это:
df.index = df.index.set_levels(df.index.levels[0].str.replace(' ', ''), level=0)
Старый, более длинный ответ:
Я обнаружил, что понимание по спискам, предложенное @Shovalt, работает, но на моей машине было медленным (с использованием фрейма данных s > 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 и часовой пояс - Ошибка замороженного списка - Переполнение стека