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

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

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

Разворачивание списков в строки через explode

До сих пор мы меняли форму таблицы, перекладывая столбцы в строки (melt) или строки в столбцы (pivot_table). Но иногда данные приходят в ещё более сжатом виде: одна ячейка содержит список значений. Например, у каждого товара — несколько тегов, у каждого заказа — список позиций.

import pandas as pd

df_tags = pd.DataFrame({
    'product': ['Стол', 'Стул', 'Лампа'],
    'tags': [['дерево', 'мебель'], ['пластик', 'мебель'], ['свет']]
})
print(df_tags)
  product                tags
0    Стол    [дерево, мебель]
1    Стул  [пластик, мебель]
2   Лампа             [свет]

Здесь в столбце tags — Python-списки, а не отдельные значения. Фильтровать, группировать или агрегировать по тегам в таком виде не получится: pandas воспринимает каждый список как единый объект.

df.explode('col') раскладывает список в отдельные строки. Каждый элемент получает свою строку, а все остальные столбцы в этой строке дублируются.

df_ex = df_tags.explode('tags')
print(df_ex)
  product     tags
0    Стол   дерево
0    Стол   мебель
1    Стул  пластик
1    Стул   мебель
2   Лампа     свет

Обрати внимание на индекс: значения 0, 0, 1, 1, 2. Pandas сохраняет исходный индекс строки и повторяет его для каждого элемента списка. Порядок строк при этом не нарушается, и позиционный доступ через .iloc работает корректно даже с повторяющимися метками.

Сброс индекса нужен в двух конкретных ситуациях:

Контракт на уникальный RangeIndex — если последующий код или внешняя функция ожидает, что индекс строго последовательный и без повторений. 2.

Доступ по метке через .loc — если обращаться к строкам по метке 0, df_ex.loc[0] вернёт сразу несколько строк, что может быть неожиданным.

df_ex = df_tags.explode('tags').reset_index(drop=True)
print(df_ex)
  product     tags
0    Стол   дерево
1    Стол   мебель
2    Стул  пластик
3    Стул   мебель
4   Лампа     свет

reset_index(drop=True) создаёт новый последовательный RangeIndex и выбрасывает старый. Параметр drop=True здесь обязателен: без него старый индекс переедет в отдельный столбец с именем index, что обычно нежелательно.

Ещё один нюанс: если в столбце встречается пустой список [], explode превратит его в строку с NaN — сигнал, что у записи не было ни одного элемента. Это не ошибка, но стоит держать в голове при дальнейшей фильтрации.

После explode с таблицей можно работать стандартными средствами: groupby('tags').size() подсчитает, сколько товаров имеет каждый тег; merge по столбцу tags присоединит справочник тегов. explode сам по себе не агрегирует — он только переводит данные в форму, удобную для последующего анализа.

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

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

О переписке

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

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

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