Коротко
stack()переносит заголовки столбцов во внутренний уровень индекса: таблица становится длиннее, из DataFrame часто получается Series с MultiIndex.unstack()делает обратное: внутренний уровень индекса становится столбцами.level=выбирает уровень по номеру или имени;fill_value=заполняет появившиеся пустые ячейки.- Частый приём:
groupby([a, b]).sum().unstack()— из двухуровневого результата сделать таблицуa × b. - В отличие от
melt/pivot, здесь всё строится вокруг индекса, а не обычных столбцов.
DataFrame
| city | jan | feb |
|---|---|---|
| Омск | 120 | 130 |
| Тула | 95 | 105 |
Series с MultiIndex
| city | month | |
|---|---|---|
| Омск | jan | 120 |
| feb | 130 | |
| Тула | jan | 95 |
| feb | 105 |
Синтаксис
df.stack(level=-1)
s.unstack(level=-1, fill_value=None)
df.groupby(["a", "b"])["x"].sum().unstack(fill_value=0)Параметры
ПараметрЧто делаетПо умолчанию
levelкакой уровень переносить: номер или имя; по умолчанию внутренний-1fill_valueв unstack: чем заполнить сочетания, которых не былоNoneПримеры
wide = pd.DataFrame(
{"jan": [120, 95], "feb": [130, 105]},
index=pd.Index(["Омск", "Тула"], name="city"),
)
wide.columns.name = "month"wide.stack() # столбцы → внутренний уровень индексаВывод
city month
Омск jan 120
feb 130
Тула jan 95
feb 105
dtype: int64wide.stack().unstack() # внутренний уровень индекса → столбцыВывод
month jan feb city Омск 120 130 Тула 95 105
wide.stack().unstack(level="city") # в столбцы можно перенести любой уровеньВывод
city Омск Тула month jan 120 95 feb 130 105
sales = pd.DataFrame({
"city": ["Омск", "Омск", "Тула", "Тула", "Омск"],
"drink": ["латте", "чай", "латте", "латте", "латте"],
"cups": [30, 12, 18, 25, 20],
})
sales.groupby(["city", "drink"])["cups"].sum().unstack(fill_value=0) # частый приём после groupbyВывод
drink латте чай city Омск 50 12 Тула 43 0
Подводные камни
stack сохраняет пропуски
with_gap = wide.astype(float)
with_gap.loc["Тула", "feb"] = np.nan
with_gap.stack() # pandas 3: строка с NaN сохраняетсяВывод
city month
Омск jan 120.0
feb 130.0
Тула jan 95.0
feb NaN
dtype: float64wide.stack(dropna=True)Ошибка
ValueError: dropna must be unspecified as the new implementation does not introduce rows of NA values. This argument will be removed in a future version of pandas.
Чтобы убрать пропуски, вызовите .dropna() после stack().