달나라 노트

Python Pandas : stack, unstack (pivot하기, pivot 풀기) 본문

Python/Python numpy

Python Pandas : stack, unstack (pivot하기, pivot 풀기)

CosmosProject 2026. 5. 20. 21:39
728x90
반응형

Pandas stack() / unstack() — 데이터를 넓은 형태와 긴 형태로 변환하는 메서드

열을 행으로 접거나(stack), 행 인덱스를 열로 펼치는(unstack) 메서드입니다. MultiIndex 데이터를 다룰 때 핵심이 되는 한 쌍의 역함수입니다.

핵심 개념 — 넓은 형태 vs 긴 형태

데이터는 넓은 형태(wide)긴 형태(long) 두 가지로 표현할 수 있습니다.

넓은 형태 (wide)          긴 형태 (long)
─────────────────         ──────────────────────
분기   Q1   Q2            지역  분기  매출
지역                      부산  Q1    80
부산   80  120     ←→     부산  Q2   120
서울  100  150            서울  Q1   100
                          서울  Q2   150

      unstack() ←
      → stack()
  stack() unstack()
방향 열 → 행 인덱스 행 인덱스 → 열
결과 형태 긴 형태 (long) 넓은 형태 (wide)
반환 타입 MultiIndex Series DataFrame
주 사용처 분석/집계용 변환 피벗 테이블, 시각화 준비

기본 문법

DataFrame.stack(level=-1)                        # 가장 안쪽 열 레벨을 행으로
DataFrame.unstack(level=-1, fill_value=None)     # 가장 안쪽 행 레벨을 열로

stack() — 열을 행으로 접기

import pandas as pd

wide = pd.DataFrame({
    'Q1': [80, 100],
    'Q2': [120, 150]
}, index=['부산', '서울'])

print(wide)
#       Q1   Q2
# 부산   80  120
# 서울  100  150

long = wide.stack()
print(long)
# 부산  Q1     80
#      Q2    120
# 서울  Q1    100
#      Q2    150
# dtype: int64

열(Q1, Q2)이 행 인덱스의 안쪽 레벨로 내려와 MultiIndex Series가 됩니다.


unstack() — 행을 열로 펼치기

stack()의 결과를 다시 원래대로 되돌립니다.

wide_again = long.unstack()
print(wide_again)
#       Q1   Q2
# 부산   80  120
# 서울  100  150

level 파라미터 — 어떤 레벨을 올릴지 선택

MultiIndex가 여러 레벨일 때 어떤 레벨을 열로 올릴지 지정합니다. groupby로 집계한 결과가 대표적인 예입니다.

# groupby로 만든 MultiIndex Series
grouped = df.groupby(['지역', '분기'])['매출'].sum()
# 지역  분기
# 부산  Q1     80
#      Q2    120
# 서울  Q1    100
#      Q2    150

grouped.unstack()          # level=-1 (기본): 분기 → 열
# 분기   Q1   Q2
# 지역
# 부산   80  120
# 서울  100  150

grouped.unstack(level=0)   # level=0: 지역 → 열
# 지역  부산  서울
# 분기
# Q1     80   100
# Q2    120   150

fill_value — 빈 자리 채우기

데이터에 없는 조합이 생기면 기본적으로 NaN이 채워집니다.

# 부산 Q2 데이터가 없는 경우
grouped.unstack()
# 분기      Q1     Q2
# 지역
# 부산     80.0   NaN   ← 빈 자리
# 서울    100.0  150.0

grouped.unstack(fill_value=0)
# 분기   Q1   Q2
# 지역
# 부산   80    0
# 서울  100  150

응용 사례 1 — 월별 카테고리 매출 피벗

sales = pd.DataFrame({
    '월':      [1, 1, 2, 2, 3, 3],
    '카테고리': ['식품', '전자', '식품', '전자', '식품', '전자'],
    '매출':    [200, 500, 180, 620, 220, 480]
})

# groupby 집계 → unstack으로 피벗
pivot = sales.groupby(['월', '카테고리'])['매출'].sum().unstack(fill_value=0)
# 카테고리  식품  전자
# 월
# 1        200  500
# 2        180  620
# 3        220  480

# 다시 긴 형태로 되돌리고 싶을 때
pivot.stack().reset_index()
#    월 카테고리  매출
# 0   1     식품   200
# 1   1     전자   500
# ...

피벗 형태는 .plot()으로 바로 시각화가 가능합니다.


응용 사례 2 — 교차 분석 및 비율 계산

survey = pd.DataFrame({
    '성별':   ['남', '남', '여', '여', '남', '여'],
    '만족도': ['만족', '불만', '만족', '만족', '만족', '불만'],
})

# 성별 × 만족도 카운트
count = survey.groupby(['성별', '만족도']).size().unstack(fill_value=0)
# 만족도  만족  불만
# 성별
# 남       2    1
# 여       2    1

# 행별 비율 계산
ratio = count.div(count.sum(axis=1), axis=0).round(2)
# 만족도  만족  불만
# 성별
# 남      0.67  0.33
# 여      0.67  0.33

stack() / unstack() 역함수 관계

original  = pivot               # 넓은 형태
stacked   = pivot.stack()       # 긴 형태로 접기
restored  = stacked.unstack()   # 다시 넓은 형태로 복원

# original == restored  (완전히 동일)
핵심 직관: stack은 표를 세로로 접고, unstack가로로 펼칩니다. 둘은 완전한 역함수 관계라 df.stack().unstack()은 원본과 동일합니다.
728x90
반응형
Comments