pandas: группировки, соединения и упорядоченные показатели

melt, pivot_table и explode: широкий и длинный форматы

Содержание курса

Как melt переводит таблицу из широкого формата в длинный

df.melt собирает несколько столбцов значений в два: название исходного столбца и его значение. Идентификаторы из id_vars сохраняются. Например, оценки по предметам можно собрать в столбцы «предмет» и «оценка»:

import pandas as pd
df = pd.DataFrame({"student": ["Аня"], "math": [8], "physics": [9]})
long = df.melt(id_vars="student", value_vars=["math", "physics"],
               var_name="subject", value_name="score")
print(long.to_dict(orient="records"))

Результат:

[{'student': 'Аня', 'subject': 'math', 'score': 8}, {'student': 'Аня', 'subject': 'physics', 'score': 9}]

pivot_table строит сводную таблицу и агрегирует повторяющиеся сочетания ключей; explode разворачивает элементы списков внутри ячеек в отдельные строки. Это разные преобразования. Ниже разберём, как выбрать операцию под структуру данных.

В предыдущем уроке мы соединяли таблицы через merge и concat — операции, которые работают по горизонтали и вертикали, но не меняют саму структуру данных. Сейчас займёмся другим: научимся переформатировать таблицу целиком — переводить её из широкого представления в длинное и обратно.

Широкий и длинный форматы: зачем переводить данные

Возьмём простую таблицу с оценками студентов:

| student | math | physics | |---------|------|---------| | Аня | 85 | 90 | | Боря | 70 | 65 |

Это широкий формат (wide): каждый предмет — отдельный столбец. Для чтения глазами удобно, но для анализа — нет. Если нужно отфильтровать все оценки ниже 80, или сгруппировать результаты по предмету, или подсчитать среднее по каждому предмету через groupby — придётся писать отдельный код для каждого столбца.

Проблема решается переходом к длинному формату (long или tidy), где одна строка = одно наблюдение по одному измерению:

| student | subject | score | |---------|---------|-------| | Аня | math | 85 | | Аня | physics | 90 | | Боря | math | 70 | | Боря | physics | 65 |

Теперь df[df['score'] < 80] даёт все слабые результаты сразу, а groupby('subject')['score'].mean() считает среднее по каждому предмету одной строкой — независимо от того, сколько предметов в таблице.

Для этого перевода в pandas есть pd.melt.

import pandas as pd

df_wide = pd.DataFrame({
    'student': ['Аня', 'Боря'],
    'math': [85, 70],
    'physics': [90, 65]
})

df_long = pd.melt(
    df_wide,
    id_vars=['student'],           # столбцы-идентификаторы — остаются неизменными
    value_vars=['math', 'physics'],  # столбцы, которые «разворачиваем» в строки
    var_name='subject',            # как назвать столбец с именами бывших столбцов
    value_name='score'             # как назвать столбец со значениями
)
print(df_long)

Вывод:

  student  subject  score
0     Аня     math     85
1    Боря     math     70
2     Аня  physics     90
3    Боря  physics     65

Что происходит внутри: каждый столбец из value_vars становится набором строк. Столбцы из id_vars дублируются для каждого такого столбца. Итоговое число строк — len(df) × len(value_vars), то есть 2 × 2 = 4.

Параметры по смыслу: — id_vars — «якорные» столбцы, которые идентифицируют запись. В нашем примере это student. Они не разворачиваются, а просто повторяются в каждой строке результата.

  • value_vars — столбцы, которые нужно превратить в строки. Если пропустить этот параметр, pandas возьмёт все столбцы, кроме тех, что в id_vars, — иногда это удобно, но лучше указывать явно.
  • var_name и value_name — имена двух новых столбцов. По умолчанию pandas называет их variable и value, что неинформативно; всегда стоит задавать свои имена.

Широкий формат удобен для ввода данных вручную и для отчётов. Длинный — для аналитических операций: фильтрации по единому столбцу значений, группировки через groupby, объединения с другими таблицами через merge. pd.melt — это переключатель между ними в одну сторону. Обратное преобразование с агрегацией делает pd.pivot_table, о котором — в следующем разделе.

Начать заново?

Помощник начнёт новый диалог по этой задаче. Текущая переписка останется в истории до конца срока хранения.

О переписке

Можно приложить до трёх фото PNG, JPEG или WebP по 5 МБ.

Переписка и фото хранятся 90 дней после последнего принятого сообщения. Преподаватель получит доступ к диалогу, когда вы попросите его помочь.

Проверка решения остаётся отдельным действием.