
pandas groupby는 데이터를 어떤 기준으로 묶고, 각 묶음마다 계산한 뒤, 결과를 다시 합칠 때 씁니다. 문법보다 먼저 잡아야 할 감각은 “기준별로 나눠서 계산한다”입니다.
예를 들어 매출 데이터가 있을 때 전체 매출만 보는 것은 쉽습니다. 하지만 지점별 매출, 상품별 평균 단가, 고객별 주문 횟수를 보고 싶다면 행을 그룹으로 나누는 기준이 필요합니다.
pandas 공식 문서는 groupby를 split-apply-combine 흐름으로 설명합니다. 이 글도 그 흐름을 기준으로 보겠습니다.
pandas groupby를 떠올리는 기준

pandas groupby는 split-apply-combine이다
split은 데이터를 기준별 그룹으로 나누는 단계입니다. apply는 각 그룹에 계산을 적용하는 단계입니다. combine은 그 결과를 하나의 Series나 DataFrame으로 다시 모으는 단계입니다. Python 프로젝트 환경 자체가 아직 헷갈린다면 pyproject.toml 글을 먼저 보고 와도 좋습니다.
import pandas as pd
orders = pd.DataFrame({
"store": ["A", "A", "B", "B", "B"],
"product": ["coffee", "tea", "coffee", "tea", "coffee"],
"amount": [5000, 4000, 5500, 4200, 5300],
})
by_store = orders.groupby("store")["amount"].sum()
print(by_store)위 코드는 store 값을 기준으로 행을 나눈 뒤, 각 store 그룹의 amount 합계를 계산합니다. 결과는 지점별 매출 요약입니다.
agg는 그룹별 요약을 만들 때 쓴다
agg는 aggregation, 즉 집계입니다. 그룹마다 하나의 요약값 또는 몇 개의 요약값을 만들 때 씁니다.
summary = orders.groupby("store").agg(
total_amount=("amount", "sum"),
avg_amount=("amount", "mean"),
order_count=("amount", "count"),
)
print(summary)이 결과는 원래 행 5개가 아니라 store A, B처럼 그룹 수만큼 줄어듭니다. 그래서 보고서용 요약표를 만들 때 잘 맞습니다.
실무에서는 여기서 한 걸음 더 나아가 날짜, 지점, 상품을 함께 묶는 경우가 많습니다. 예를 들어 월별·지점별 매출을 보고 싶다면 groupby([“month”, “store”])처럼 기준을 여러 개 줄 수 있습니다.
orders["month"] = ["2026-07", "2026-07", "2026-07", "2026-08", "2026-08"]
monthly = orders.groupby(["month", "store"]).agg(
total_amount=("amount", "sum"),
order_count=("amount", "count"),
)
print(monthly)이때 결과 index가 여러 단계로 보이면 당황할 수 있습니다. 그 구조가 불편하면 reset_index()로 다시 일반 열처럼 풀어주면 됩니다.
transform은 원래 행에 그룹 계산 결과를 붙일 때 쓴다
transform은 그룹별 계산을 하되, 결과를 원래 행 개수에 맞춰 돌려줍니다. 그래서 각 주문 행에 지점별 평균이나 지점별 합계를 붙이고 싶을 때 유용합니다.
orders["store_avg"] = orders.groupby("store")["amount"].transform("mean")
orders["diff_from_store_avg"] = orders["amount"] - orders["store_avg"]
print(orders)agg는 표를 줄이고, transform은 원래 표에 계산 결과를 붙입니다. 이 차이만 잡아도 groupby 실수의 절반은 줄어듭니다.
예를 들어 각 주문이 자기 지점 평균보다 높은지 낮은지 보고 싶다면 transform이 맞습니다. 반대로 지점별 평균만 따로 보고 싶다면 agg가 맞습니다. 결과표의 행 수가 줄어드는지 유지되는지를 먼저 생각하면 선택이 쉬워집니다.
groupby에서 자주 헷갈리는 옵션
groupby를 처음 쓰면 계산보다 결과 모양에서 자주 막힙니다. 특히 sort, dropna, as_index 같은 옵션이 그렇습니다.
- sort=False: 그룹 키를 정렬하지 않고 원래 등장 순서를 더 잘 보존하고 싶을 때 검토한다
- dropna=False: 그룹 기준 열의 NaN도 하나의 그룹으로 보고 싶을 때 쓴다
- as_index=False: 그룹 키를 index가 아니라 일반 열로 받고 싶을 때 쓴다
- reset_index(): 이미 만들어진 그룹 결과를 다시 평평한 표로 바꿀 때 쓴다
이 옵션들은 고급 기술이라기보다 결과표를 사람이 읽기 좋은 모양으로 만드는 도구입니다.
질문을 바꾸면 groupby 모양도 바뀐다
groupby를 잘 쓰려면 먼저 데이터에게 묻는 질문을 정확히 써보는 것이 좋습니다. 같은 주문 데이터라도 질문이 바뀌면 groupby 기준과 계산 방식이 달라집니다.
# 질문 1. 지점별 총매출은?
orders.groupby("store")["amount"].sum()
# 질문 2. 지점과 상품별 평균 주문 금액은?
orders.groupby(["store", "product"])["amount"].mean()
# 질문 3. 각 주문이 자기 지점 평균보다 큰가?
avg = orders.groupby("store")["amount"].transform("mean")
orders["above_store_avg"] = orders["amount"] > avg첫 번째와 두 번째 질문은 결과가 요약표로 줄어드니 agg 계열이 맞습니다. 세 번째 질문은 원래 주문 행마다 True/False를 붙여야 하므로 transform이 맞습니다.
이렇게 질문을 먼저 쓰면 groupby가 덜 무섭습니다. “무엇으로 묶을까”, “그룹마다 무엇을 계산할까”, “결과가 줄어들어도 되는가” 세 가지만 보면 됩니다.
pivot_table과 groupby는 언제 구분할까
pivot_table은 행과 열로 교차표를 만들 때 편합니다. groupby는 그룹별 계산을 단계적으로 다루기 좋습니다. 결과를 표 형태로 넓게 보고 싶으면 pivot_table, 계산 흐름을 세밀하게 제어하고 싶으면 groupby가 자연스럽습니다.
처음에는 apply보다 기본 연산을 먼저 본다
pandas 문서는 built-in GroupBy 연산을 여러 단계로 쓰는 편이 사용자 정의 Python 함수를 apply로 돌리는 것보다 효율적일 수 있다고 설명합니다. 그래서 처음부터 apply로 모든 것을 해결하려고 하기보다 sum, mean, count, agg, transform을 먼저 봐야 합니다.
- 그룹별 합계: sum
- 그룹별 평균: mean
- 여러 집계: agg
- 원래 행에 붙이기: transform
- 복잡한 사용자 정의 로직: apply
정리
pandas groupby는 문법 암기보다 질문을 바꾸는 도구입니다. “전체가 얼마인가?”에서 “기준별로 보면 어떻게 다른가?”로 관점을 바꾸는 순간 groupby가 필요해집니다.
처음에는 split-apply-combine, agg와 transform 차이, pivot_table과의 역할 차이만 확실히 잡아도 충분합니다.