| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- CSS
- Typescript
- PowerShell
- scaler
- value_counts
- RandomAccessFile
- podman
- Python
- FileChannel
- vscode
- Vite
- Webpack
- Mode
- scikit-learn
- yaml
- io
- 정렬
- UV
- tauri
- Ollama
- Docker Compose
- json schema
- vim
- curl
- json
- docker
- pandas
- 최빈값
- Java
- cli
- Today
- Total
워로디스
Pandas. groupby 자주 쓰이는 패턴 본문
pandas의 groupby()는 데이터 분석에서 정말 자주 쓰이는 기능입니다.
핵심은 특정 컬럼을 기준으로 데이터를 그룹으로 묶고, 그룹별로 계산하는 것입니다.
실무에서 자주 사용하는 패턴 6가지만 알아도 대부분의 기본적인 집계 작업을 처리할 수 있습니다.
0. 예제 데이터
아래 데이터를 기준으로 설명하겠습니다.
import pandas as pd
df = pd.DataFrame({
"region": ["서울", "서울", "부산", "부산", "서울", "부산"],
"category": ["식품", "가전", "식품", "가전", "식품", "식품"],
"customer": ["A", "B", "A", "C", "B", "D"],
"sales": [100, 300, 200, 400, 150, 100]
})
| region | category | customer | sales | |
|---|---|---|---|---|
| 0 | 서울 | 식품 | A | 100 |
| 1 | 서울 | 가전 | B | 300 |
| 2 | 부산 | 식품 | A | 200 |
| 3 | 부산 | 가전 | C | 400 |
| 4 | 서울 | 식품 | B | 150 |
| 5 | 부산 | 식품 | D | 100 |
1. 가장 기본: 그룹별 합계, 평균
가장 많이 사용하는 형태입니다.
# 지역별 매출 합계
df.groupby("region")["sales"].sum()
결과:
region
부산 700
서울 550
Name: sales, dtype: int64
평균, 최댓값, 최솟값도 똑같은 방식입니다.
df.groupby("region")["sales"].mean()
df.groupby("region")["sales"].max()
df.groupby("region")["sales"].min()
기본 구조
df.groupby("그룹기준")["계산할컬럼"].집계함수()
2. 여러 컬럼을 기준으로 그룹화
지역뿐만 아니라 상품 카테고리별로도 매출을 나누고 싶을 때 사용합니다.
df.groupby(["region", "category"])["sales"].sum()
결과:
region category
부산 가전 400
식품 300
서울 가전 300
식품 250
여기서 reset_index()를 붙이면 일반적인 DataFrame 형태로 바꿀 수 있습니다.
df.groupby(["region", "category"])["sales"].sum().reset_index()
| region | category | sales |
|---|---|---|
| 부산 | 가전 | 400 |
| 부산 | 식품 | 300 |
| 서울 | 가전 | 300 |
| 서울 | 식품 | 250 |
같은 결과를 더 간결하게 얻는 방법도 있습니다.
df.groupby(
["region", "category"],
as_index=False
)["sales"].sum()
실무에서는 후속 처리를 쉽게 하려고 as_index=False를 자주 사용합니다.
3. agg(): 여러 통계를 한 번에 계산
특히 추천하는 패턴입니다. 합계, 평균, 건수 등을 한 번에 구할 수 있습니다.
df.groupby("region").agg(
total_sales=("sales", "sum"),
avg_sales=("sales", "mean"),
max_sales=("sales", "max")
)
결과:
| region | total_sales | avg_sales | max_sales |
|---|---|---|---|
| 부산 | 700 | 233.33 | 400 |
| 서울 | 550 | 183.33 | 300 |
문법은 다음과 같습니다.
새로운컬럼명=("원본컬럼명", "집계함수")
조금 더 실무적인 예제입니다.
summary = df.groupby("region", as_index=False).agg(
total_sales=("sales", "sum"),
avg_sales=("sales", "mean"),
order_count=("sales", "size"),
customer_count=("customer", "nunique")
)
이렇게 하면 지역별 매출 합계, 평균, 주문 건수, 고유 고객 수를 한 번에 구할 수 있습니다.
4. size(), count(), nunique(): 개수 세기
세 함수의 차이를 알아두면 좋습니다.
| 함수 | 의미 |
|---|---|
size() |
그룹에 속한 전체 행 개수 |
count() |
특정 컬럼에서 결측치가 아닌 값의 개수 |
nunique() |
특정 컬럼의 고유한 값 개수 |
# 지역별 전체 행 개수
df.groupby("region").size()
# 지역별 sales가 결측치가 아닌 행 개수
df.groupby("region")["sales"].count()
# 지역별 고유 고객 수
df.groupby("region")["customer"].nunique()
특히 size()와 count()는 결측치(NaN)가 있을 때 결과가 달라질 수 있다는 점을 기억하면 됩니다.
5. transform(): 그룹별 계산 결과를 원본 행에 붙이기
agg()만큼 알아두면 유용한 함수입니다.
일반적인 groupby() 집계는 그룹별로 행이 줄어들지만, transform()은 원본 DataFrame과 같은 행 개수를 유지합니다.
예를 들어 각 행에 해당 지역의 전체 매출을 붙이고 싶다면:
df["region_total"] = (
df.groupby("region")["sales"].transform("sum")
)
df["sales_ratio"] = df["sales"] / df["region_total"]
결과 일부:
| region | sales | region_total | sales_ratio |
|---|---|---|---|
| 서울 | 100 | 550 | 0.182 |
| 서울 | 300 | 550 | 0.545 |
| 부산 | 200 | 700 | 0.286 |
| 부산 | 400 | 700 | 0.571 |
| 서울 | 150 | 550 | 0.273 |
| 부산 | 100 | 700 | 0.143 |
각 행의 매출이 해당 지역 전체 매출에서 차지하는 비율을 계산했습니다.
이 패턴은 그룹별 비율, 그룹 평균과의 차이, 그룹별 정규화 등을 할 때 많이 사용합니다.
예를 들어 지역 평균보다 매출이 높은 행만 추출할 수도 있습니다.
df[
df["sales"] > df.groupby("region")["sales"].transform("mean")
]
6. 집계한 뒤 정렬하기
그룹별 집계 후 크기순으로 정렬하는 작업도 매우 흔합니다.
summary = (
df.groupby("region", as_index=False)
.agg(total_sales=("sales", "sum"))
.sort_values("total_sales", ascending=False)
)
결과:
| region | total_sales |
|---|---|
| 부산 | 700 |
| 서울 | 550 |
sort_values()의 ascending=False는 내림차순이라는 의미입니다.
이 구조는 지역별 매출 순위, 상품별 판매량 순위, 사용자별 활동량 순위 등에 그대로 적용할 수 있습니다.
정리
| 패턴 | 주로 사용하는 상황 |
|---|---|
groupby().sum() |
그룹별 합계 |
groupby(["A", "B"]) |
여러 기준으로 그룹화 |
groupby().agg() |
여러 집계값을 동시에 계산 |
groupby().size() |
그룹별 데이터 개수 |
groupby().nunique() |
그룹별 고유값 개수 |
groupby().transform() |
그룹별 값을 원본 행에 적용 |
groupby() + sort_values() |
그룹별 집계 결과의 순위 계산 |
가장 먼저 groupby + agg + as_index=False 조합을 익히는 것을 추천합니다.
result = (
df.groupby(["region", "category"], as_index=False)
.agg(
total_sales=("sales", "sum"),
avg_sales=("sales", "mean"),
order_count=("sales", "size")
)
.sort_values("total_sales", ascending=False)
)
이 패턴 하나만 익숙해져도 실무에서 자주 작성하는 요약 테이블을 상당 부분 만들 수 있습니다.
그다음 transform()을 익히면 단순 집계를 넘어 그룹별 평균 비교, 비율 계산, 그룹 내 상대적인 값 계산까지 자연스럽게 확장할 수 있습니다.
'Data Science > Pandas' 카테고리의 다른 글
| Pandas. value_counts(), idxmax(), mode()와 MultiIndex 정리 (0) | 2026.10.19 |
|---|---|
| Pandas. df[...]와 .loc[...]의 행 또는 열 선택 기준 (0) | 2026.09.28 |
| Pandas. value_counts() 용례 (0) | 2026.09.28 |
| Pandas. 최빈값 (0) | 2026.09.23 |
| Pandas. apply() 정리 — 함수의 입력과 출력 (0) | 2026.08.27 |
