본문으로 건너뛰기
김신건의 로그

[Pandas] stack / unstack

· 수정 · 📖 약 2분 · 555자/단어 #python #pandas #reshape #multiindex #wide-long
Pandas stack, Pandas unstack, Pandas stack-unstack, Pandas stack / unstack, MultiIndex 변환, pandas wide long 변환

정의

  • stack() : 가장 안쪽 컬럼 레벨 -> 행 레벨 (DataFrame -> Series 또는 더 좁은 DataFrame)
  • unstack() : 가장 안쪽 행 레벨 -> 컬럼 레벨

Pandas pivot / Pandas melt 의 MultiIndex 기반 버전.

사용 상황

  • groupby 결과 wide 변환: groupby(['region', 'product']).sum()unstack('product') 로 product 별 컬럼
  • 시계열 패널 -> wide format: 날짜 + 종목 MultiIndex를 날짜 행 + 종목 컬럼으로
  • wide -> long 변환: 여러 컬럼 (Q1, Q2, Q3, Q4)을 stack() 으로 긴 형태로
  • pivot_table 결과 정리: MultiIndex 컬럼이 생겼을 때 stack() 으로 조정

pivot/melt 가 이미 있는 경우 대부분 충분하다. stack/unstack이미 MultiIndex가 있거나 자동 생성된 경우에 가장 자연스럽다.

변환 흐름 시각화

flowchart LR
    W["Wide DataFrame"] -->|"stack()"| L["Long MultiIndex Series"]
    L -->|"unstack()"| W

    P["pivot 결과"] -.->|"unstack 과 동일"| W
    M["melt 결과"] -.->|"stack 과 동일"| L

stack 기본

python
import pandas as pd
df = pd.DataFrame(
  {'math': [90, 80], 'english': [85, 75]},
  index=['Alice', 'Bob']
)
print(df)
print('--- stack ---')
print(df.stack())
결과
       math  english
Alice    90       85
Bob      80       75
--- stack ---
Alice  math       90
     english    85
Bob    math       80
     english    75
dtype: int64

DataFrame 의 2 컬럼이 MultiIndex Series 로 합쳐졌다.

unstack 기본

s.unstack()                  # 가장 안쪽 index level -> columns
s.unstack(level=0)           # 0번 level 을 columns 로
s.unstack(level='product')   # 이름으로 지정 (권장)

# 역변환: stack 으로 복원
multi = df.stack()           # Series
multi.unstack()              # 원래 DataFrame 으로 복원

다단계 unstack

df = pd.DataFrame({
    'region': ['Seoul', 'Seoul', 'Busan', 'Busan'],
    'product': ['A', 'B', 'A', 'B'],
    'sales': [100, 200, 150, 250],
}).set_index(['region', 'product'])['sales']

df.unstack()                # product 가 컬럼
df.unstack(level='region')  # region 이 컬럼
python
import pandas as pd
s = pd.Series([100, 200, 150, 250],
  index=pd.MultiIndex.from_tuples(
      [('Seoul','A'),('Seoul','B'),('Busan','A'),('Busan','B')],
      names=['region','product']
  ))
print(s.unstack())
결과
product    A    B
region
Busan    150  250
Seoul    100  200
region \ productAB
Busan150250
Seoul100200

pivot / melt 와의 비교

동작DataFrame APIMultiIndex API
long -> widepivot, pivot_tableunstack
wide -> longmeltstack

대부분의 경우 pivot / melt 가 더 직관적. stack / unstack 은 MultiIndex 가 이미 있는 경우 자연스럽다.

# 같은 결과 (다른 경로)
df.pivot(index='region', columns='product', values='sales')
df.set_index(['region', 'product'])['sales'].unstack('product')

groupby + unstack 패턴

# groupby 가 MultiIndex 결과를 반환 -> unstack 으로 wide 형태
df.groupby(['region', 'product'])['sales'].sum().unstack('product')

이 패턴은 실무에서 매우 자주 쓰인다. groupby + agg + unstack 조합:

result = (
    df.groupby(['region', 'product', 'quarter'])['sales']
    .sum()
    .unstack('quarter')
    .fillna(0)
)

fill_value

s.unstack(fill_value=0)      # NaN 을 0 으로

stack 의 dropna

df.stack(dropna=False)       # NaN 도 결과에 포함 (기본은 제거)

pandas 2.x 에서 stack 의 기본 동작이 변경됨: future_stack=True 모드가 기본이 됨. NaN 처리 방식 확인 필요.

실전 패턴

분기별 wide 보고서

import pandas as pd

data = {
    'region': ['Seoul', 'Seoul', 'Seoul', 'Busan', 'Busan', 'Busan'],
    'quarter': ['Q1', 'Q2', 'Q3', 'Q1', 'Q2', 'Q3'],
    'revenue': [100, 120, 130, 80, 90, 95],
}
df = pd.DataFrame(data)

# long -> wide: region 행, quarter 컬럼
wide = (
    df.groupby(['region', 'quarter'])['revenue']
    .sum()
    .unstack('quarter')
    .fillna(0)
)
print(wide)
# quarter    Q1     Q2     Q3
# region
# Busan    80.0   90.0   95.0
# Seoul   100.0  120.0  130.0

wide -> long 정리

# 여러 시점 컬럼을 long format 으로
df_wide = pd.DataFrame({
    'region': ['Seoul', 'Busan'],
    'Q1': [100, 80],
    'Q2': [120, 90],
    'Q3': [130, 95],
}).set_index('region')

df_long = df_wide.stack().reset_index()
df_long.columns = ['region', 'quarter', 'revenue']

MultiIndex 컬럼 unstack 후 평탄화

result = df.groupby(['region', 'product']).agg({'sales': ['sum', 'mean']})
# 컬럼: MultiIndex ('sales', 'sum'), ('sales', 'mean')

# unstack 으로 region 을 컬럼 레벨로
wide = result['sales'].unstack('region')
# 컬럼: MultiIndex ('sum', 'Seoul'), ('sum', 'Busan'), ('mean', 'Seoul'), ...

# 평탄화
wide.columns = ['_'.join(c) for c in wide.columns]

pandas 2.x 스타일: stack() 동작 확인

import pandas as pd

# pandas 2.x 에서 stack 은 MultiIndex 컬럼도 처리
df = pd.DataFrame(
    {'A': {'x': 1, 'y': 2}, 'B': {'x': 3, 'y': 4}}
)
# pandas 2.x default: future_stack=True
stacked = df.stack(future_stack=True)

성능

상황권장
unstack() 후 sparseNaN 폭증 주의, long-format 유지 권장
대용량 wide -> longmelt()stack() 보다 빠를 수 있음
대용량 long -> widepivot_table() 또는 unstack() 비슷, 테스트 후 선택
반복 stack() / unstack()중간 결과 캐싱: 인터미디어트 DataFrame 저장
# 대용량에서 unstack NaN 폭증 방지: sparse 확인
before = s.memory_usage(deep=True)
after = s.unstack().memory_usage(deep=True).sum()
print(f"메모리 증가: {after / before:.1f}x")

함정

1. stack 한 결과의 타입

  • DataFrame.stack() -> Series (일반: 컬럼이 1개 레벨)
  • DataFrame.stack(level=0) -> DataFrame (남은 컬럼 레벨이 있으면)

2. unstack 의 level 지정

s.unstack()                 # 가장 안쪽 level (기본)
s.unstack(level=-1)         # 같음
s.unstack(level=0)          # 가장 바깥 level
s.unstack(level='product')  # 이름으로 (권장, 명확)

3. 데이터가 너무 sparse 하면 NaN 폭증

# 10 region x 1000 product 의 unstack -> 10000 셀 대부분 NaN
# 이런 경우 long-format 유지가 메모리 효율적

4. pandas 2.x stack() 변경사항

WARNING

pandas 2.x 에서 stack() 의 기본 동작이 변경됐다. FutureWarning 가 발생하면 future_stack=True 를 명시적으로 전달하라.

# pandas 2.x: FutureWarning 방지
df.stack(future_stack=True)   # 새 동작 명시적 사용

관련 위키

이 글의 용어 (7개)
[Pandas] 성능 / 메모리 최적화pandas
정의 pandas 의 흔한 성능 함정과 최적화 패턴. 벡터화 + dtype 선택 + 알고리즘 의 조합이 핵심. 사용 상황 | 상황 | 권장 접근 | |:---|:---| | 단순…
[Pandas] DataFramepandas
정의 은 2차원 레이블 테이블. 각 열이 , 모든 열이 같은 (행 라벨) 를 공유. SQL 테이블 / Excel 시트 / R data.frame 의 Python 대응체. 구조 시…
[Pandas] groupbypandas
정의 는 데이터를 그룹으로 나누고 (split), 각 그룹에 함수를 적용 (apply), 결과를 합쳐 (combine) 새 DataFrame 으로 만드는 split-apply-c…
[Pandas] meltpandas
정의 는 의 역방향. wide-format → long-format 변환. 여러 컬럼을 두 컬럼 ( , ) 으로 합친다. 장기간 시계열 데이터나 시각화 라이브러리 (seaborn…
[Pandas] MultiIndexpandas
정의 MultiIndex 는 여러 단계(level)의 라벨로 구성된 . SQL의 composite key와 비슷하며, 그룹화된 데이터를 자연스럽게 표현한다. , , 등이 자동으로…
[Pandas] pivotpandas
정의 는 long-format → wide-format 변환. 한 열의 고유 값들이 새 컬럼이 되고, 원래 데이터는 그 자리에 배치된다. 집계가 없으므로 같은 (index, co…
[Pandas] pivot_tablepandas
정의 는 의 확장. 집계 함수를 동반 해 중복 (index, columns) 도 처리. Excel 의 피벗 테이블과 가장 가까운 기능. pivottable 처리 흐름 사용 상황 …

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기