Как стать автором
Обновить
1099.38
OTUS
Цифровые навыки от ведущих экспертов

Сложная агрегация в Pandas с MultiIndex

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров2K

Привет, Хабр!

Сегодня поговорим о Pandas MultiIndex — мощной штуке, которая спасла меня, когда пришлось агрегировать кучу многомерных данных. В отчётах за несколько лет с миллионами строк, обычный groupby() просто не справлялся, а MultiIndex сделал всё красиво и быстро. Разберём, как использовать его для сложных операций, не тратя лишнего времени.

Работа с MultiIndex

Создание MultiIndex

Создать MultiIndex в Pandas проще, чем может показаться. Есть несколько способов, и они зависят от того, с какими данными ты работаешь. Например, у тебя может быть DataFrame с несколькими столбцами, которые логически должны представлять вложенные индексы. В таком случае поможет метод set_index():

import pandas as pd

# пример данных с несколькими уровнями
data = {
    'country': ['USA', 'USA', 'Canada', 'Canada'],
    'city': ['New York', 'Los Angeles', 'Toronto', 'Vancouver'],
    'year': [2020, 2020, 2020, 2020],
    'population': [8.4, 4.0, 2.9, 2.5]
}

df = pd.DataFrame(data)

# Создание MultiIndex
df_multi = df.set_index(['country', 'city'])
print(df_multi)

На выходе у тебя будет DataFrame с двухуровневым индексом country и city. Теперь ты можешь выполнять операции на этих уровнях, как на обычных индексах, но с дополнительными возможностями.

Управление уровнями индексов

Окей, создали мы MultiIndex. Но что, если нужно добавить новый уровень или поменять местами уже существующие? Pandas предоставляет для этого несколько инструментов.

Добавление уровня индекса: метод set_index() можно использовать и для добавления индексов поверх уже существующих.

# Добавление индекса 'year' как еще одного уровня
df_multi = df_multi.set_index('year', append=True)
print(df_multi)

Переупорядочение уровней: для этого используем метод swaplevel(). Например, если нужно поменять местами страну и город:

df_reordered = df_multi.swaplevel('country', 'city')
print(df_reordered)

Удаление уровней индексов: это делается с помощью метода reset_index(), который "сбрасывает" один или несколько уровней индекса обратно в столбцы.

df_reset = df_multi.reset_index('city')
print(df_reset)

stack() и unstack(): работа с вложенными данными

Методы stack() и unstack() позволяют преобразовывать уровни индексов в столбцы и наоборот:

  • stack(): превращает уровни столбцов в уровни индексов. Мастхев для "поворота" данных в более компактный вид.

df_stacked = df_multi.stack()
print(df_stacked)
  • unstack(): обратная операция, превращающая индекс обратно в столбцы.

df_unstacked = df_multi.unstack()
print(df_unstacked)

Агрегация данных с MultiIndex

Теперь переходим к самому важному — как MultiIndex помогает выполнять сложные агрегации данных. Сложные многомерные группировки и агрегации можно реализовать на базе groupby() и agg(). Допустим, есть DataFrame с данными по годам и месяцам, и хотим агрегировать данные по нескольким уровням сразу.

Пример группировки по нескольким уровням:

# Допустим, у нас есть данные о продажах за несколько лет по странам и городам
data = {
    'country': ['USA', 'USA', 'Canada', 'Canada'],
    'city': ['New York', 'Los Angeles', 'Toronto', 'Vancouver'],
    'year': [2020, 2020, 2020, 2021],
    'sales': [100, 200, 150, 130]
}

df = pd.DataFrame(data)
df_multi = df.set_index(['country', 'city', 'year'])

# Группируем по странам и считаем общие продажи
df_grouped = df_multi.groupby(level='country').sum()
print(df_grouped)

Этот код покажет нам суммарные продажи по странам за все годы. Но можно пойти еще дальше и агрегировать данные по уровням внутри уровней. Например, используя agg(), можно комбинировать разные типы агрегации:

df_aggregated = df_multi.groupby(level='country').agg({'sales': ['sum', 'mean']})
print(df_aggregated)

Здесь считаем одновременно и сумму, и среднее по продажам для каждого уровня.

Работа с срезами данных по уровням MultiIndex

Когда есть MultiIndex, стандартные методы доступа к данным типа .loc[] становятся еще более мощными. Например, можно извлечь данные по одному уровню или по комбинации уровней.

  • Доступ к данным через .loc[]:

# Доступ к данным для определенного города
print(df_multi.loc[('USA', 'New York')])
  • Использование .xs() для выборки данных по конкретному уровню:

# Получение данных по конкретному году
print(df_multi.xs(2020, level='year'))

Прочие полезные фичи

Не останавливаемся. Вот несколько полезных фич, которые могут пригодится в работе с MultiIndex:

  1. Проверка наличия MultiIndex: иногда нужно быстро проверить, есть ли MultiIndex в DataFrame.

print(df_multi.index.is_multi)
  1. Получение имен уровней:

print(df_multi.index.names)
  1. Распаковка уровней индексов в столбцы для упрощения работы:

df_flat = df_multi.reset_index()
print(df_flat)
  1. Совмещение нескольких индексов в один уровень: когда нужно скомбинировать несколько индексов в один, можно использовать pd.MultiIndex.from_tuples().

new_index = pd.MultiIndex.from_tuples([('USA', 2020), ('Canada', 2021)], names=['country', 'year'])

Вот так Pandas MultiIndex превращает сложные многомерные данные в легко управляемые структуры, где агрегация и манипуляция уровнями выполняются в пару строк. Если ваши данные сложнее обычных таблиц, MultiIndex — это ваш лучший друг.

Освоить мощные навыки анализа данных — анализ требований + статистика + BI и получить востребованную профессию можно на курсе «Аналитик данных».

Теги:
Хабы:
Всего голосов 12: ↑11 и ↓1+16
Комментарии2

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS