Pandas 그룹화 및 데이터 집계 기법

데이터 분석에서의 그룹화와 집계

데이터를 그룹으로 나누고 각 그룹에 대해 통계적 요약이나 변환 작업을 수행하는 것은 데이터 분석의 핵심 절차 중 하나입니다. Pandas는 groupby 메커니즘을 통해 이 과정을 직관적이고 효율적으로 지원합니다. 이를 통해 사용자는 데이터셋을 조각화하고, 그룹별로 평균, 합계, 표준편차 등의 지표를 산출하거나, 사용자 정의 함수를 적용할 수 있습니다.

주요 활용 분야는 다음과 같습니다:

  • 그룹 단위의 요약 통계 계산 (예: 평균, 개수, 최댓값)
  • 그룹 내 데이터 변환 (예: 정규화, 순위 부여)
  • 피벗테이블 및 교차집계표 생성
  • 분위수 기반 구간 분석

10.1 그룹화의 작동 원리 (GroupBy Mechanics)

그룹화 연산은 일반적으로 "분할(Split) → 적용(Apply) → 병합(Combine)"의 세 단계로 설명됩니다. 이 과정에서 데이터는 특정 기준(그룹 키)에 따라 분할되고, 각 그룹에 함수가 적용된 후 결과가 통합됩니다.

기본 예제


# 샘플 데이터 생성
data = {
    'Team': ['Riders', 'Riders', 'Devils', 'Devils', 'Kings', 'kings', 'Kings', 'Kings', 'Riders', 'Royals', 'Royals', 'Riders'],
    'Rank': [1, 2, 2, 3, 3, 4, 1, 1, 2, 4, 1, 2],
    'Year': [2014, 2015, 2014, 2015, 2014, 2015, 2016, 2017, 2016, 2014, 2015, 2017],
    'Points': [876, 789, 863, 673, 741, 812, 756, 788, 694, 701, 804, 690]
}
df = pd.DataFrame(data)

# 그룹 객체 생성
grouped = df.groupby('Team')

# 그룹 정보 확인
print(grouped.groups.keys())  # 그룹 이름 출력

# 수치형 열에 대한 평균 계산
team_avg = grouped.mean()

# 다중 기준 그룹화
multi_group = df.groupby(['Team', 'Year'])
print(multi_group.size())

# 특정 그룹 추출
group_2014 = df.groupby('Year').get_group(2014)

# 필터링: 그룹 내 행 수가 3 이상인 팀만 선택
filtered = df.groupby('Team').filter(lambda x: len(x) >= 3)

특정 열 선택 및 반복 처리

그룹화 시 일부 열만 대상으로 삼을 수 있으며, 반복문을 통해 각 그룹을 개별적으로 처리할 수 있습니다.


# 특정 열만 그룹화하여 평균 산출
points_by_team_year = df['Points'].groupby([df['Team'], df['Year']]).mean()

# 반복 처리 (단일 키)
for team, group_data in df.groupby('Team'):
    print(f"팀: {team}")
    print(group_data)

# 다중 키 반복
for (team, year), group_data in df.groupby(['Team', 'Year']):
    print(f"{team}, {year} 년")

데이터 타입 또는 인덱스 기준 그룹화

열의 데이터 타입(dtype)이나 계층적 인덱스(level)를 기준으로 그룹화할 수도 있습니다.


# dtype 기준으로 열 그룹화
type_groups = df.groupby(df.dtypes, axis=1)
type_dict = dict(list(type_groups))

# 계층적 컬럼 인덱스 예시
columns = pd.MultiIndex.from_arrays(
    [['US', 'US', 'US', 'JP', 'JP'], [1, 3, 5, 1, 3]],
    names=['country', 'tenor']
)
hierarchical_df = pd.DataFrame(np.random.randn(4, 5), columns=columns)

# country 레벨 기준 집계
hierarchical_df.groupby(level='country', axis=1).count()

10.2 데이터 집계 (Aggregation)

집계는 배열 형태의 데이터를 하나의 스칼라 값으로 변환하는 작업을 의미합니다. Pandas는 기본 통계 함수 외에도 사용자 정의 함수를 지원합니다.

윈도우 기반 집계


# 롤링 윈도우 평균
ts_df = pd.DataFrame(
    np.random.randn(10, 4),
    index=pd.date_range('2020-01-01', periods=10),
    columns=['A', 'B', 'C', 'D']
)

rolling_mean = ts_df.rolling(window=3).mean()           # 3개씩 평균
partial_roll = ts_df.rolling(window=3, min_periods=2).mean()  # 최소 2개 포함
centered_roll = ts_df.rolling(window=3, center=True).mean()    # 중심 정렬

aggregate() 함수 활용

agg() 또는 aggregate()를 사용하면 여러 함수를 동시에 적용할 수 있습니다.


r = ts_df.rolling(window=3, min_periods=2)

# 단일/다중 열에 여러 함수 적용
r['A'].agg(['sum', 'mean'])
r[['A', 'B']].agg(['sum', 'std'])

# 열별 다른 함수 적용
r.agg({'A': 'mean', 'B': 'sum'})

기타 확장 집계 기법


# 누적 집계 (expanding)
ts_df.expanding(min_periods=3).mean()

# 지수 가중 평균 (EWMA)
ts_df.ewm(com=0.5).mean()

10.3 그룹 기반 변환과 apply

그룹화 후에는 단순 집계뿐만 아니라 데이터 변환도 가능합니다.

transform(): 결과 재구조화

transform은 그룹별 계산 결과를 원본 인덱스에 맞게 방사형(broadcast)으로 확장합니다.


people = pd.DataFrame(
    np.random.randn(5, 5),
    columns=list('abcde'),
    index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis']
)

key_labels = ['one', 'two', 'one', 'two', 'one']

# 그룹 평균 계산 후 각 행에 동일한 값 부여
group_means = people.groupby(key_labels).transform(np.mean)

apply(): 유연한 사용자 정의 함수

apply는 복잡한 로직을 적용할 때 유용합니다.


def top_n_rows(group, n=2, col='data1'):
    return group.sort_values(by=col, ascending=False).head(n)

result = df.groupby('key2').apply(top_n_rows, n=2, col='data1')
result_no_keys = df.groupby(['key1', 'key2'], group_keys=False).apply(top_n_rows, n=1)

버킷 및 분위수 분석

데이터를 구간(bucket)으로 나누어 분석할 수 있습니다.


frame = pd.DataFrame({
    'data1': np.random.randn(1000),
    'data2': np.random.randn(1000)
})

# 등간격 구간 생성
bins = pd.cut(frame['data1'], 4, labels=['Q1', 'Q2', 'Q3', 'Q4'])

def summary_stats(x):
    return pd.Series({
        'min': x.min(),
        'max': x.max(),
        'count': x.count(),
        'avg': x.mean()
    })

frame['data2'].groupby(bins).apply(summary_stats).unstack()

# 등비 구간 (분위수 기반)
quantile_bins = pd.qcut(frame['data1'], 10, labels=False)
frame['data2'].groupby(quantile_bins).apply(summary_stats).unstack()

10.4 피벗테이블과 교차집계

다차원 요약표를 생성하기 위한 주요 도구입니다.

피벗테이블


pd.pivot_table(
    data=df,
    values='Points',
    index='Team',
    columns='Year',
    aggfunc='mean',
    fill_value=0,
    margins=True
)

교차집계표 (crosstab)


pd.crosstab(df['Team'], df['Year'], margins=True)

태그: pandas groupby Aggregation transform pivot_table

6월 25일 01:44에 게시됨