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 сам по себе не агрегирует — он только переводит данные в форму, удобную для последующего анализа.
