14. 멀티인덱싱과 그룹화
🎯 이 장의 목표
- 그룹화(group-by)로 데이터를 그룹별로 묶어 요약한다
- split-apply-combine 흐름을 이해한다
- 멀티인덱싱(여러 층 인덱스)이 무엇인지 안다
💡 팁
"남자/여자별 평균 매출", "요일별 손님 수"처럼 그룹별로 나눠 요약하는 것은 데이터 분석에서 가장 자주 하는 일입니다. 그 핵심 도구가 groupby입니다.먼저: 그룹화(group-by)가 뭔가요?
그룹화(grouping)는 같은 값을 가진 행끼리 묶은 뒤, 각 묶음을 요약(평균·합계 등)하는 것입니다. 예를 들어 손님 데이터를 "요일별로 묶어 평균 매출"을 구하는 식이죠.
이 과정은 세 단계로 일어나며, 이를 split-apply-combine이라 부릅니다.
flowchart LR
A[전체 데이터] -->|Split<br/>그룹으로 쪼갬| B[서울 그룹]
A -->|Split| C[부산 그룹]
B -->|Apply<br/>각 그룹 요약| D[서울 평균]
C -->|Apply| E[부산 평균]
D -->|Combine<br/>결과 합침| F[도시별 평균 표]
E -->|Combine| F
classDef raw fill:#fff3bf,stroke:#f59f00,color:#000
classDef grp fill:#c3fae8,stroke:#0ca678,color:#000
classDef res fill:#d3f9d8,stroke:#2f9e44,color:#000
class A raw
class B,C,D,E grp
class F res
🔑 새 용어 — split-apply-combine
그룹화의 세 단계입니다. Split(기준값으로 그룹을 쪼갬) → Apply(각 그룹에 평균 등을 적용) → Combine(결과를 하나의 표로 합침). Pandas의groupby가 이 셋을 한 번에 해 줍니다.
기본 그룹화
실습 데이터를 만듭니다.
PYTHON
import pandas as pd df = pd.DataFrame({ "도시": ["서울", "부산", "서울", "부산", "서울"], "성별": ["남", "남", "여", "여", "남"], "매출": [100, 150, 200, 120, 180] }) print(df)
이제 도시별 평균 매출을 구해 봅시다.
PYTHON
print(df.groupby("도시")["매출"].mean())
실행 결과:
CODE
도시 부산 135.0 서울 160.0 Name: 매출, dtype: float64
읽는 법: df.groupby("도시") (도시로 쪼갬) → ["매출"] (매출 열을) → .mean() (평균 내라). 부산 평균은 (150+120)/2=135, 서울은 (100+200+180)/3≈160입니다.
다른 요약도 똑같은 패턴입니다.
PYTHON
print(df.groupby("도시")["매출"].sum()) # 도시별 합계 print(df.groupby("도시")["매출"].count()) # 도시별 개수 print(df.groupby("도시")["매출"].max()) # 도시별 최댓값
실행 결과:
CODE
도시 부산 270 서울 480 Name: 매출, dtype: int64 도시 부산 2 서울 3 Name: 매출, dtype: int64 도시 부산 150 서울 200 Name: 매출, dtype: int64
여러 기준으로 그룹화
기준 열을 리스트로 주면 여러 단계로 묶입니다 (예: 도시 그리고 성별).
PYTHON
print(df.groupby(["도시", "성별"])["매출"].mean())
실행 결과:
CODE
도시 성별
부산 남 150.0
여 120.0
서울 남 140.0
여 200.0
Name: 매출, dtype: float64
결과의 왼쪽을 보면 도시와 성별이 두 층의 인덱스를 이룹니다. 이것이 다음에 볼 멀티인덱스입니다.
여러 요약을 한 번에 — agg
agg(aggregate, 집계)로 여러 통계를 동시에 구할 수 있습니다.
PYTHON
print(df.groupby("도시")["매출"].agg(["mean", "sum", "count", "max"]))
실행 결과:
CODE
mean sum count max 도시 부산 135.0 270 2 150 서울 160.0 480 3 200
💡 팁
한눈에 그룹별 여러 지표를 보고 싶을 때 agg가 편리합니다. df.groupby("도시").agg({"매출": "sum", "성별": "count"})처럼 열마다 다른 요약을 줄 수도 있습니다.멀티인덱싱: 여러 층의 인덱스
🔑 새 용어 — 멀티인덱스(MultiIndex)
인덱스(행 이름표)가 한 층이 아니라 여러 층으로 된 것입니다. 위groupby(["도시","성별"])결과처럼 "도시 안에 성별"이 들어가는 계층 구조를 표현합니다.
멀티인덱스 결과에서 특정 부분을 꺼낼 때는 .loc를 씁니다.
PYTHON
grouped = df.groupby(["도시", "성별"])["매출"].mean() print(grouped.loc["서울"]) # 서울 전체 print("---") print(grouped.loc["서울", "여"]) # 서울 + 여
실행 결과:
CODE
성별 남 140.0 여 200.0 Name: 매출, dtype: float64 --- 200.0
복잡한 멀티인덱스는 reset_index()로 평범한 표로 펴는 경우가 많습니다. 다루기가 훨씬 쉬워집니다.
PYTHON
flat = df.groupby(["도시", "성별"])["매출"].mean().reset_index() print(flat)
실행 결과:
CODE
도시 성별 매출 0 부산 남 150.0 1 부산 여 120.0 2 서울 남 140.0 3 서울 여 200.0
💡 팁
입문 단계 팁: 멀티인덱스가 헷갈리면, group-by 결과 끝에 .reset_index()를 붙여 평범한 표로 펴서 다루세요. 대부분의 작업이 훨씬 직관적이 됩니다.value_counts: 가장 간단한 빈도 집계
특정 열의 값별 개수를 셀 때는 value_counts()가 가장 간편합니다(group-by의 단축형).
PYTHON
print(df["도시"].value_counts())
실행 결과:
CODE
도시 서울 3 부산 2 Name: count, dtype: int64
💡 "어떤 값이 몇 번 나오나"를 빠르게 볼 때 애용됩니다. 범주형 데이터(7장 카운트플롯) 분석의 출발점입니다.
🛠 미니 챌린지
PYTHON
import pandas as pd df = pd.DataFrame({ "부서": ["영업", "개발", "영업", "개발", "영업"], "직급": ["사원", "사원", "대리", "대리", "사원"], "연봉": [3000, 3500, 4000, 4200, 3200] })
- 부서별 평균 연봉을 구하세요.
- 부서별·직급별 평균 연봉을 구하세요.
- 부서별로 연봉의 합계·평균·인원수를
agg로 한 번에 구하세요.
✅ 미니 챌린지 해설
PYTHON
# 1. 부서별 평균 print(df.groupby("부서")["연봉"].mean())
실행 결과:
CODE
부서 개발 3850.0 영업 3400.0 Name: 연봉, dtype: float64
PYTHON
# 2. 부서별·직급별 평균 print(df.groupby(["부서", "직급"])["연봉"].mean())
실행 결과:
CODE
부서 직급
개발 대리 4200.0
사원 3500.0
영업 대리 4000.0
사원 3133.333333
Name: 연봉, dtype: float64
PYTHON
# 3. agg로 한 번에 print(df.groupby("부서")["연봉"].agg(["sum", "mean", "count"]))
실행 결과:
CODE
sum mean count 부서 개발 7700 3850.0 2 영업 10200 3400.0 3
이 장에서 배운 것
- 그룹화는 split-apply-combine(쪼개기-적용-합치기)으로 그룹별 요약을 만든다.
df.groupby("열")["대상"].mean()이 기본 패턴이며, sum·count·max 등도 같다.- 여러 기준(
groupby(["A","B"]))은 멀티인덱스 결과를 낳는다. agg로 여러 통계를 한 번에,value_counts로 값별 빈도를 빠르게 센다.- 멀티인덱스가 복잡하면
reset_index()로 평범한 표로 펴서 다룬다.
✍️ 확인 문제
- split-apply-combine의 세 단계는 각각 무엇을 하나요?
df.groupby("도시")["매출"].sum()은 무엇을 구하나요?- 한 열의 값별 개수를 가장 간단히 세는 메서드는 무엇인가요?
데이터를 합치고 요약하는 법까지 익혔습니다! 이제 결과를 눈으로 보는 시각화로 넘어갑니다. 먼저 가장 기본인 Matplotlib입니다.
👉 15. Matplotlib 기초 그래프