Коротко
- Широкий формат: у каждой сущности одна строка, показатели по периодам — в отдельных столбцах. Длинный: одна строка на пару «сущность — период».
melt(id_vars=…)— из широкого в длинный: остальные столбцы превращаются в пары «имя столбца (var_name) — значение (value_name)».pivot(index, columns, values)— из длинного в широкий, без агрегации: каждому сочетанию должно соответствовать одно значение.- Если значений на сочетание несколько, нужен pivot_table с
aggfunc. - Длинный формат удобен для
groupby, фильтров и графиков; широкий — для чтения человеком.
Широкий формат
| city | jan | feb |
|---|---|---|
| Омск | 120 | 130 |
| Тула | 95 | 105 |
Длинный формат
| city | month | cups |
|---|---|---|
| Омск | jan | 120 |
| Тула | jan | 95 |
| Омск | feb | 130 |
| Тула | feb | 105 |
Синтаксис
df.melt(id_vars=None, value_vars=None, var_name="variable", value_name="value")
df.pivot(index=None, columns=None, values=None)Параметры
ПараметрЧто делаетПо умолчанию
id_varsв melt: столбцы, которые остаются как есть (идентификаторы)Nonevalue_varsв melt: какие столбцы «расплавить»; по умолчанию все, кроме id_varsNonevar_name / value_nameв melt: имена новых столбцов для имён и значений"variable" / "value"index / columns / valuesв pivot: что станет строками, столбцами и значениямиобязательныйПримеры
wide = pd.DataFrame({
"city": ["Омск", "Тула"],
"jan": [120, 95],
"feb": [130, 105],
})long = wide.melt(id_vars="city", var_name="month", value_name="cups")
longВывод
city month cups 0 Омск jan 120 1 Тула jan 95 2 Омск feb 130 3 Тула feb 105
long = wide.melt(id_vars="city", var_name="month", value_name="cups")
long.pivot(index="city", columns="month", values="cups")Вывод
month feb jan city Омск 130 120 Тула 105 95
wide.melt(id_vars="city", value_vars=["feb"]) # только часть столбцовВывод
city variable value 0 Омск feb 130 1 Тула feb 105
long = wide.melt(id_vars="city", var_name="month", value_name="cups")
back = long.pivot(index="city", columns="month", values="cups").reset_index()
back.columns.name = None # убрать имя «month» над столбцами
backВывод
city feb jan 0 Омск 130 120 1 Тула 105 95
long = wide.melt(id_vars="city", var_name="month", value_name="cups")
long.groupby("month")["cups"].sum() # длинный формат удобен для groupby и графиковВывод
month feb 235 jan 215 Name: cups, dtype: int64
Подводные камни
pivot и повторяющиеся сочетания
pivot не знает, что делать с двумя значениями для одной ячейки.
dup = pd.DataFrame({"city": ["Омск", "Омск"], "month": ["jan", "jan"], "cups": [120, 80]})
dup.pivot(index="city", columns="month", values="cups") # два значения на одну ячейкуОшибка
ValueError: Index contains duplicate entries, cannot reshape
dup = pd.DataFrame({"city": ["Омск", "Омск"], "month": ["jan", "jan"], "cups": [120, 80]})
dup.pivot_table(index="city", columns="month", values="cups", aggfunc="sum")Вывод
month jan city Омск 200
pivot сортирует столбцы
Новые столбцы идут по алфавиту: в примере выше feb оказался раньше jan. Нужный порядок задайте явно: wide[["city", "jan", "feb"]], или сделайте столбец месяца упорядоченной категорией.