Коротко
- MultiIndex — метка строки из нескольких частей (уровней). Появляется после
set_index([a, b]),groupby([a, b]),pivot_table,stack. df.loc["Омск"]— все строки внешнего уровня; полная метка — кортежdf.loc[("Омск", "фев")].xs("янв", level="month")— срез по любому уровню.pd.IndexSlice— срезы по нескольким уровням сразу; индекс должен быть отсортирован (sort_index()).swaplevel,droplevel,get_level_values— работа с уровнями;reset_index()— обратно в плоскую таблицу.
Синтаксис
df.set_index(["a", "b"])
df.loc["x"], df.loc[("x", "y")], df.loc[("x", "y"), "col"]
df.xs("y", level="b")
idx = pd.IndexSlice; df.sort_index().loc[idx[:, ["y1", "y2"]], :]
df.swaplevel(), df.droplevel("b"), df.index.get_level_values("a")Параметры
ПараметрЧто делаетПо умолчанию
levelуровень по имени или номеру (в xs, droplevel, groupby, reset_index)обязательныйdrop_levelв xs: убрать уровень, по которому сделан срезTrueПримеры
sales = pd.DataFrame({
"city": ["Омск", "Омск", "Омск", "Тула", "Тула", "Сочи"],
"month": ["янв", "фев", "мар", "янв", "фев", "янв"],
"cups": [120, 130, 110, 95, 105, 60],
"rating": [4.5, 4.6, 4.4, 4.0, 4.1, 4.8],
}).set_index(["city", "month"])salesВывод
cups rating
city month
Омск янв 120 4.5
фев 130 4.6
мар 110 4.4
Тула янв 95 4.0
фев 105 4.1
Сочи янв 60 4.8sales.loc["Омск"] # все строки внешнего уровняВывод
cups rating month янв 120 4.5 фев 130 4.6 мар 110 4.4
sales.loc[("Тула", "фев"), "cups"] # полная метка — кортежВывод
np.int64(105)
sales.xs("янв", level="month") # срез по внутреннему уровнюВывод
cups rating city Омск 120 4.5 Тула 95 4.0 Сочи 60 4.8
idx = pd.IndexSlice
sales.sort_index().loc[idx[:, ["янв", "фев"]], "cups"] # любые города, два месяцаВывод
city month Омск янв 120 Сочи янв 60 Тула янв 95 Омск фев 130 Тула фев 105 Name: cups, dtype: int64
print(sales.index.names)
sales.index.get_level_values("city").unique()Вывод
['city', 'month'] Index(['Омск', 'Тула', 'Сочи'], dtype='str', name='city')
print(sales.swaplevel().sort_index().head(3))
sales.droplevel("month").head(3)Вывод
cups rating
month city
мар Омск 110 4.4
фев Омск 130 4.6
Тула 105 4.1
cups rating
city
Омск 120 4.5
Омск 130 4.6
Омск 110 4.4sales.groupby(level="city")["cups"].sum() # группировка по уровню индексаВывод
city Омск 360 Сочи 60 Тула 200 Name: cups, dtype: int64
Подводные камни
Срезы по неотсортированному индексу
Срез по меткам уровня (loc["Омск":"Тула"], IndexSlice) требует отсортированного индекса, иначе UnsortedIndexError. Выбор одной метки работает и без сортировки. Вызывайте sort_index() перед срезами.
sales.loc["Омск":"Тула"] # «Сочи» стоит после «Тулы» — индекс не отсортированОшибка
UnsortedIndexError: 'Key length (1) was greater than MultiIndex lexsort depth (0)'
sales.sort_index().loc["Омск":"Тула"]Вывод
cups rating
city month
Омск мар 110 4.4
фев 130 4.6
янв 120 4.5
Сочи янв 60 4.8
Тула фев 105 4.1
янв 95 4.0MultiIndex там, где проще плоская таблица
Для экспорта, merge и большинства операций удобнее обычные столбцы. Если уровни мешают — reset_index().
sales.reset_index().head(3) # обратно в обычные столбцыВывод
city month cups rating 0 Омск янв 120 4.5 1 Омск фев 130 4.6 2 Омск мар 110 4.4