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

[Pandas] MultiIndex

· 수정 · 📖 약 1분 · 139자/단어 #python #pandas #multiindex #hierarchical
Pandas MultiIndex, 계층 인덱스, hierarchical index

정의

MultiIndex 는 여러 단계 (level) 의 라벨로 구성된 Pandas Index. SQL 의 composite key 와 비슷, 그룹화된 데이터를 자연스럽게 표현.

생성

# from_tuples
mi = pd.MultiIndex.from_tuples(
    [('Seoul', 'A'), ('Seoul', 'B'), ('Busan', 'A')],
    names=['city', 'dept']
)

# from_product (직교곱)
mi = pd.MultiIndex.from_product(
    [['Seoul', 'Busan'], ['A', 'B']],
    names=['city', 'dept']
)

# groupby 결과
df.groupby(['city', 'dept']).sum().index   # 자동으로 MultiIndex

인덱싱

python
import pandas as pd
mi = pd.MultiIndex.from_tuples(
  [('Seoul','A'),('Seoul','B'),('Busan','A'),('Busan','B')],
  names=['city','dept']
)
df = pd.DataFrame({'sales':[100,200,150,250]}, index=mi)
print(df)
print('---')
print(df.loc['Seoul'])           # outer level
print('---')
print(df.loc[('Seoul','A')])     # tuple 로 양쪽 level
결과
             sales
city  dept
Seoul A        100
    B        200
Busan A        150
    B        250
---
    sales
dept
A       100
B       200
---
sales    100
Name: (Seoul, A), dtype: int64
citydeptsales
SeoulA100
SeoulB200
BusanA150
BusanB250

slice / cross-section

df.xs('Seoul', level='city')          # cross-section
df.xs('A', level='dept')

# slice
df.loc[(slice(None), 'A'), :]         # 모든 city 의 dept='A'
df.loc[pd.IndexSlice[:, 'A'], :]      # 같음, 더 짧음
idx = pd.IndexSlice
df.loc[idx[:, 'A'], :]

stack / unstack 으로 변환

df.unstack('dept')                    # dept 가 컬럼 level 로
df.stack()                            # 컬럼 → index

level 조작

df.reset_index()                              # MultiIndex 해제 → 일반 컬럼
df.reset_index(level='dept')                  # 일부만 해제
df.swaplevel('city', 'dept')                  # level 순서 바꿈
df.sort_index(level=['city', 'dept'])         # level 별 정렬
df.droplevel('dept')                          # level 제거

groupby 와의 자연스러운 결합

# groupby 결과는 자동 MultiIndex
result = df.groupby(['city', 'dept'])['sales'].sum()
result.unstack('dept')              # 시각화에 좋은 wide format

MultiIndex 컬럼

행뿐 아니라 컬럼도 multi-level 가능.

df.pivot_table(index='city', columns=['dept', 'quarter'], values='sales')
# 컬럼이 (dept, quarter) MultiIndex

평탄화

df.columns = ['_'.join(map(str, c)) for c in df.columns]
# ('sales', 'A') → 'sales_A'

함정

1. tuple vs list

df.loc[('Seoul', 'A')]      # 단일 인덱스
df.loc[[('Seoul', 'A')]]    # 리스트 (DataFrame)
df.loc['Seoul', 'A']        # 행 라벨 + 컬럼 라벨로 해석 (다른 의미!)

2. SettingWithCopyWarning

MultiIndex 에서 더 자주 발생. 항상 .loc[idx, col] = 한 줄로.

3. sort 가 안 된 MultiIndex

df.loc['Seoul':'Busan']    # PerformanceWarning, lexsort 안 됨
df = df.sort_index()       # 정렬 후 사용

참고

이 글의 용어 (3개)
[Pandas] groupbypandas
정의 는 데이터를 그룹으로 나누고 (split), 각 그룹에 함수를 적용 (apply), 결과를 합쳐 (combine) 새 DataFrame 으로 만드는 split-apply-c…
[Pandas] Indexpandas
정의 는 행 / 열 라벨을 보관하는 객체. / 의 모든 라벨은 Index. 정렬, 정합성, 빠른 lookup 의 기반. 기본은 RangeIndex (0, 1, 2, ...) 지만…
[Pandas] stack / unstackpandas
정의 - : 가장 안쪽 컬럼 레벨 → 행 레벨 (DataFrame → Series 또는 더 좁은 DataFrame) - : 가장 안쪽 행 레벨 → 컬럼 레벨 / 의 MultiIn…

이 개념을 다룬 위키 페이지 (2)

💬 댓글

사이트 검색 / 명령어

검색

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