Skip to main content

피벗과 Melt

같은 데이터도 구조에 따라 분석 방법이 달라집니다. 와이드(wide) 형식은 열이 많고 행이 적은 구조, 롱(long) 형식은 행이 많고 열이 적은 구조입니다. Pandas는 이 두 형식 간 변환을 위한 도구를 제공합니다.

학습 목표

  • 와이드 형식과 롱 형식의 차이를 이해한다
  • pivot_table로 데이터를 와이드 형식으로 변환할 수 있다
  • melt로 와이드 데이터를 롱 형식으로 변환할 수 있다
  • stack/unstack으로 인덱스와 열 간 변환을 수행할 수 있다

왜 중요한가

시각화 라이브러리(Seaborn)와 ML 모델은 각각 다른 형식의 데이터를 요구합니다. Seaborn의 대부분의 함수는 롱 형식을, sklearn은 와이드 형식(피처 행렬)을 기대합니다. 데이터 재구조화 능력은 효율적인 분석의 핵심입니다.

pivot_table

import pandas as pd
import numpy as np

df = pd.DataFrame({
    '부서': ['개발', '개발', '영업', '영업', '마케팅', '마케팅'],
    '분기': ['Q1', 'Q2', 'Q1', 'Q2', 'Q1', 'Q2'],
    '매출': [100, 120, 80, 90, 60, 75],
    '인원': [10, 12, 8, 8, 5, 6]
})

# 기본 피벗 테이블
pivot = df.pivot_table(
    values='매출',          # 집계할 값
    index='부서',           # 행이 될 열
    columns='분기',         # 열이 될 열
    aggfunc='sum'           # 집계 함수
)
print(pivot)
# 분기     Q1   Q2
# 부서
# 개발    100  120
# 마케팅   60   75
# 영업     80   90

# 다중 값 + 다중 집계
pivot2 = df.pivot_table(
    values=['매출', '인원'],
    index='부서',
    columns='분기',
    aggfunc={'매출': 'sum', '인원': 'mean'},
    margins=True,            # 합계 행/열 추가
    margins_name='전체'
)

크로스탭

# 빈도 기반 교차표
df2 = pd.DataFrame({
    '성별': ['M', 'F', 'M', 'F', 'M', 'F', 'M', 'M'],
    '구매등급': ['Gold', 'Silver', 'Gold', 'Gold', 'Silver', 'Gold', 'Silver', 'Gold']
})

ct = pd.crosstab(df2['성별'], df2['구매등급'], margins=True)
print(ct)

# 비율로 변환
ct_pct = pd.crosstab(df2['성별'], df2['구매등급'], normalize='index')
print(ct_pct)  # 행 기준 비율

melt — 와이드를 롱으로

# 와이드 형식
wide_df = pd.DataFrame({
    '학생': ['김철수', '이영희', '박민수'],
    '수학': [85, 92, 78],
    '영어': [90, 88, 95],
    '과학': [75, 80, 82]
})

# 롱 형식으로 변환
long_df = wide_df.melt(
    id_vars='학생',           # 고정할 열
    value_vars=['수학', '영어', '과학'],  # 녹일 열
    var_name='과목',          # 열 이름이 들어갈 새 열
    value_name='점수'         # 값이 들어갈 새 열
)
print(long_df)
#     학생  과목  점수
# 0  김철수  수학   85
# 1  이영희  수학   92
# 2  박민수  수학   78
# 3  김철수  영어   90
# ...

stack과 unstack

# stack: 열 → 행 (와이드 → 롱)
stacked = wide_df.set_index('학생').stack()
print(stacked)

# unstack: 행 → 열 (롱 → 와이드)
unstacked = stacked.unstack()
print(unstacked)
연산방향용도
pivot_table()롱 → 와이드집계 + 재구조화
melt()와이드 → 롱시각화 준비
stack()열 → 행 인덱스멀티인덱스 생성
unstack()행 인덱스 → 열피벗과 유사

AI/ML에서의 활용

  • 시각화 준비: Seaborn은 롱 형식을 선호하므로 melt로 변환합니다
  • 피처 행렬: sklearn은 와이드 형식(샘플 x 피처)을 요구합니다
  • 시계열 피벗: 시간을 열로 피벗하여 각 시점의 값을 피처로 사용합니다
  • 교차 분석: crosstab으로 범주형 변수 간 관계를 파악합니다
pivot()은 중복 값이 없을 때 단순 재구조화에 사용하고, pivot_table()은 중복 값이 있을 때 집계 함수(sum, mean 등)를 적용합니다. 실무에서는 pivot_table()을 더 많이 사용합니다.
melt()의 역연산은 pivot() 또는 pivot_table()입니다. melt로 롱 형식으로 변환한 데이터를 다시 와이드 형식으로 되돌릴 수 있습니다.

체크리스트

  • 와이드 형식과 롱 형식의 차이를 설명할 수 있다
  • pivot_table로 데이터를 집계하며 재구조화할 수 있다
  • melt로 와이드 데이터를 롱 형식으로 변환할 수 있다
  • crosstab으로 교차표를 생성할 수 있다
  • stack/unstack의 동작을 이해한다

다음 문서