PandasMiddleTechnical
В чём разница между stack() и unstack() в Pandas?
stack() поворачивает столбцы в строки (pivot wide→long), добавляя уровень в индекс; unstack() делает обратное — поворачивает уровень индекса в столбцы (long→wide).
stack() и unstack(): поворот осей
stack() и unstack() — парные методы для реструктуризации данных между «широким» (wide) и «длинным» (long) форматами. Они работают с MultiIndex и перемещают уровни между осями строк и столбцов.
stack() — столбцы → строки
import pandas as pd
df = pd.DataFrame(
{
"Q1": [100, 200, 300],
"Q2": [110, 210, 310],
"Q3": [120, 220, 320],
},
index=["Product_A", "Product_B", "Product_C"],
)
print(df)
# Q1 Q2 Q3
# Product_A 100 110 120
# Product_B 200 210 220
# Product_C 300 310 320
stacked = df.stack()
print(stacked)
# Product_A Q1 100
# Q2 110
# Q3 120
# Product_B Q1 200
# ...
print(type(stacked)) # Series с MultiIndex
unstack() — строки → столбцы
# Обратная операция: восстанавливаем оригинальный DataFrame
restored = stacked.unstack()
print(restored)
# Идентично исходному df
# unstack по конкретному уровню
unstacked_level0 = stacked.unstack(level=0)
print(unstacked_level0)
# Столбцы — Product_A, Product_B, Product_C
# Индекс — Q1, Q2, Q3
Работа с MultiIndex
arrays = [
["Moscow", "Moscow", "SPb", "SPb"],
["2024-Q1", "2024-Q2", "2024-Q1", "2024-Q2"],
]
mi = pd.MultiIndex.from_arrays(arrays, names=["city", "quarter"])
df_mi = pd.DataFrame(
{"revenue": [100, 110, 90, 95], "cost": [60, 65, 55, 58]},
index=mi,
)
print(df_mi)
# unstack: уровень 'quarter' → столбцы
pivoted = df_mi.unstack(level="quarter")
print(pivoted)
# MultiIndex столбцы: (revenue, 2024-Q1), (revenue, 2024-Q2), ...
# stack: убираем уровень столбцов обратно
long = pivoted.stack(level="quarter")
print(long)
stack vs melt vs pivot_table
stack()работает только с MultiIndex или именованными столбцами, возвращает Series или DataFrame.pd.melt()— более гибкий способ wide→long: явно задаёт id_vars и value_vars.df.pivot_table()— long→wide с агрегацией дубликатов;unstack()не агрегирует и бросает ошибку при дубликатах.
# Сравнение: melt vs stack
melted = pd.melt(
df.reset_index(),
id_vars="index",
value_vars=["Q1", "Q2", "Q3"],
var_name="quarter",
value_name="revenue",
)
print(melted)
Подводные камни
stack()по умолчанию отбрасывает NaN (dropna=True); чтобы сохранить пропуски, используйтеstack(dropna=False).unstack()при дублирующихся метках индекса бросаетValueError: Index contains duplicate entries; нужна агрегация черезpivot_table.- После
stack()получаете MultiIndex —.reset_index()нужен перед передачей в библиотеки, не понимающие MultiIndex. - В Pandas 2.1+ поведение
stack()изменилось (future_stack=True по умолчанию в 2.2): результат может содержать MultiIndex столбцов там, где раньше был плоский — проверяйте код при обновлении. - Порядок уровней после
unstack(level=N)зависит от N: неправильный выбор уровня даёт транспонированный результат. - Для временных рядов
unstackудобнее чемpivot, но только если нет дубликатов (одна запись на пересечение city × quarter).
Common mistakes
- Объяснять
stack vs unstackтолько синтаксисом без shape, dtype, состояния или режима выполнения. - Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
- Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.
What the interviewer is testing
- Может ли связать
stack vs unstackс реальным контрактом входов и выходов. - Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
- Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.