파이썬/데이터프레임 다루기

Pandas groupby 완전 정복: 집계부터 고급 활용까지

Data Jun 2025. 3. 24. 16:38

Pandas의 groupby()는 데이터 분석에 있어 가장 핵심적인 도구 중 하나입니다. 데이터를 그룹별로 나누고(split), 각 그룹에 연산을 적용하고(apply), 결과를 결합(combine)하는 방식으로 작동합니다. 이번 포스트에서는 groupby()의 기본 사용법부터 agg, apply, transform 등 고급 기능까지 모두 다뤄보겠습니다.

 

groupby 작동 방식

groupby()는 내부적으로 아래 세 가지 단계를 거쳐 동작합니다:

  1. Split (분할): 지정한 컬럼의 값에 따라 데이터를 여러 그룹으로 나눕니다.
  2. Apply (적용): 각 그룹에 대해 함수나 연산을 적용합니다 (mean(), sum(), 사용자 정의 함수 등).
  3. Combine (결합): 그룹별 결과를 하나의 객체로 합칩니다.

이러한 구조는 SQL의 GROUP BY와 유사하지만, 더 유연한 연산과 다양한 방식으로 결과를 다룰 수 있다는 점에서 차별화됩니다.

 

🧩 Split 형태로 직접 활용하기

groupby()로 나눈 객체는 집계를 하지 않더라도, 나눈 그룹을 직접 다룰 수 있습니다.

grouped = df.groupby('subject')

# 그룹 이름과 인덱스를 딕셔너리로 확인
print(grouped.groups)

# 특정 그룹만 가져오기
math_df = grouped.get_group('math')

# 루프를 통해 그룹별 처리
for name, group in grouped:
    print(f"[{name}]")
    print(group)

이러한 split-only 형태의 활용은 시각화, 파일 저장, 그룹별 조건 처리 등 다양한 실전 작업에서 유용하게 쓰입니다.

 

groupby 객체에서 split된 각 그룹에 대해 개별적으로 apply()나 lambda 함수를 적용할 수 있습니다. 예시로 설명드릴게요.

 

예시

import pandas as pd

df = pd.DataFrame({
    'team': ['A', 'A', 'B', 'B', 'C'],
    'score': [80, 90, 70, 60, 85]
})

# 그룹별로 서로 다른 함수 적용
def custom_logic(group):
    if group.name == 'A':
        return group['score'] * 2
    elif group.name == 'B':
        return group['score'] + 10
    else:
        return group['score'] - 5

df['modified'] = df.groupby('team').apply(custom_logic).reset_index(drop=True)

포인트

  • group.name으로 현재 그룹명이 무엇인지 접근 가능.
  • groupby().apply() 내부에서 그룹별로 다른 연산을 수행할 수 있음.
  • reset_index(drop=True)는 apply()가 생성한 다중 인덱스를 없애는 데 유용.

 

기본 사용법: 그룹별 평균 구하기

import pandas as pd

# 예제 데이터프레임
students = pd.DataFrame({
    'name': ['혜선', '종훈', '혜선', '종훈', '소원'],
    'subject': ['math', 'math', 'english', 'english', 'math'],
    'score': [90, 85, 92, 88, 75]
})

# 과목별 평균 점수
students.groupby('subject')['score'].mean()

 

여러 컬럼으로 그룹화

students.groupby(['name', 'subject'])['score'].mean()

여러 컬럼으로 그룹화하면 다중 인덱스(MultiIndex) 형태의 결과가 나옵니다.

 

다양한 집계 함수: agg()

agg()는 하나 혹은 여러 개의 집계 함수를 적용할 수 있습니다.

students.groupby('subject')['score'].agg(['mean', 'max', 'min'])

또는 컬럼별로 다른 집계 함수를 지정할 수도 있습니다.

students.groupby('subject').agg({
    'score': 'mean',
    'name': 'count'
})

 

고급 집계: 사용자 정의 함수와 lambda

students.groupby('subject')['score'].agg(lambda x: x.max() - x.min())

각 과목의 점수 범위(최대-최소)를 계산합니다.

 

 

전체 데이터프레임에 apply() 사용

apply()는 그룹별로 전체 DataFrame에 사용자 정의 함수를 적용할 때 유용합니다.

def zscore(x):
    return (x - x.mean()) / x.std()

students.groupby('subject')['score'].apply(zscore)

 

그룹별 값 유지: transform()

transform()은 그룹별 계산 결과를 원본과 동일한 길이로 반환할 때 사용합니다. 즉, 결과를 원본 DataFrame에 바로 붙이기 좋습니다.

students['subject_avg'] = students.groupby('subject')['score'].transform('mean')

 

🧩 그룹 객체 다루기

grouped = students.groupby('subject')
print(grouped.groups)         # 그룹 정보 딕셔너리
print(grouped.get_group('math'))  # 특정 그룹 가져오기

 

정리

 

마무리 Tip

  • 단순한 요약 통계: agg()
  • 그룹별 처리 후 다시 합치고 싶을 때: transform()
  • 그룹별 복잡한 로직을 적용하고 싶을 때: apply()
  • 집계를 하지 않고 그룹 단위로 나눈 데이터를 직접 다루고 싶다면 .get_group(), .groups, for 루프를 활용해보세요.