logoRawon_Log
홈블로그소개

Built with Next.js, Bun, Tailwind CSS and Shadcn/UI

AI

Pandas - 그룹별 집계, 병합과 연결

Rawon
2025년 9월 17일
목차
Pandas 그룹별 집계
멀티 인덱스 그룹별 집계
그룹화된 상태
집계(aggregation)
변환(transform)
필터(filter)
Pandas 병합과 연결
병합
연결

목차

Pandas 그룹별 집계
멀티 인덱스 그룹별 집계
그룹화된 상태
집계(aggregation)
변환(transform)
필터(filter)
Pandas 병합과 연결
병합
연결

Pandas 그룹별 집계

그룹별 집계(group by)는 데이터로부터 동일한 객체를 가진 데이터만 따로 뽑아 기술 통계 데이터를 추출하는 것입니다.

예를 들어 A반 수학 점수의 원본 데이터를 가지고 해당 데이터에서 같은 성별을 가진 학생들의 평균 점수를 구하거나 50점 이상을 받은 학생의 수를 구하는 등의 과정 입니다.

group by 명령어는 분할 → 적용 → 결합 과정을 거칩니다.

  • 분할(split) : 같은 종류의 데이터끼리 나누는 기능 (key)
  • 적용(apply) : 데이터 블록마다 sum, count, mean 등 연산 적용
  • 결합(combine) : 연산 함수가 적용된 각 블록들을 합침

위 단계를 거치면 어떤 키 값을 기준으로 통합된 통계 데이터를 얻을 수 있습니다.

예시 코드는 아래와 같습니다.

해당 데이터는 레이싱 팀이 매년 대회에 참가해서 얻은 랭크와 점수입니다.

이를 활용하여 데이터 프레임을 만들고 groupby 를 활용하여 팀별 합산 점수를 구합니다.

python
import pandas as pd
import numpy as np

ipl_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(ipl_data)

# df.groupby("묶음의 기준이 되는 열")["적용받는 열"].적용받는연산()
df.groupby("Team")["Points"].sum()

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_21.35.50.png

💡 주의사항
groupby의 결과물은 항상 시리즈 객체 입니다.

멀티 인덱스 그룹별 집계

한 개 이상의 열을 기준으로 그룹별 집계를 실행하는 방법을 말합니다.

  • 리스트를 사용하여 여러 개의 열 이름을 기준으로 넣으면 여러 열이 키 값이 되어 결과를 출력
  • 계층적 인덱스(hierarchical index) 형태

이전 예시에서 사용한 데이터를 활용해서 여러 열을 key 값으로, points를 추출하고 sum 연산을 적용해보겠습니다.

python
multi_groupby = df.groupby(["Team", "Year"])["Points"].sum()
multi_groupby

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_21.40.26.png

💡 한개 이상의 열로 그룹별 집계를 수행하면 여러 열이 모두 인덱스로 반환됨

인덱스 추출

python
multi_groupby["Devils":"Kings"]

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_21.43.16.png

unstack 함수는 기존 인덱스를 기준으로 묶인 곳에서 두번째 인덱스에 해당하는 것을 열로 변환해서 엑셀의 피봇테이블 같은 형태로 변환 합니다.

아래 예시코드에서 두번째 인덱스였던 year가 열로 변환된 것을 볼 수 있습니다.

python
multi_groupby.unstack()

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_21.43.27.png

swaplevel 함수를 사용하면 인덱스 간의 레벨을 변경할 수 있습니다.

python
multi_groupby.swaplevel()

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_21.45.21.png

sort_index 함수를 사용하면 첫번째 인덱스를 기준으로 데이터를 재정렬 합니다.

python
multi_groupby.swaplevel().sort_index()

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_21.45.34.png


그룹화된 상태

그룹화된 상태라는 말의 의미는 group by의 단계인 분할 → 적용 → 결합 중에서 분할 까지만 이루어진 상태를 의미하며,

get_group 함수를 사용하여 해당 키 값을 기준으로 분할된 데이터프레임 객체를 확인 할 수 있습니다.

python
grouped = df.groupby("Team")
grouped.get_group("Riders")

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_21.47.34.png


집계(aggregation)

요약된 통계정보를 추출하는 집계를 구현하기 위해서는 agg 함수를 사용합니다.

  • agg 함수 : min, numpy의 mean 등 기존 함수 그대로 적용
python
grouped.agg(min)

grouped.agg(np.mean)

변환(transform)

변환은 집계와는 달리 키 값별로 요약된 정보가 아닌 개별 데이터 변환을 지원합니다.

또한, 적용 시점에서는 그룹화된 상태의 값으로 적용됩니다.

python
grouped.transform(max)

score = lambda x: (x - x.mean()) / x.std()
grouped.transform(score)

필터(filter)

특정 조건으로 데이터를 검색할 때 사용하는 함수 이며, 주로 filter 함수를 사용합니다.

python
df.groupby('Team').filter(lambda x: len(x) >= 4)

Pandas 병합과 연결

병합

병합(merge)는 두개의 데이터를 특정한 기준을 가지고 하나로 통합하는 작업을 의미합니다.

SQL에서는 join 이라는 표현을 주로 사용 합니다.

  • inner join
  • full join
  • left join
  • right join
python
import pandas as pd # pandas 모듈 호출

raw_data = {
    'subject_id': ['1', '2', '3', '4', '5', '7', '8', '9', '10', '11'],
    'test_score': [51, 15, 15, 61, 16, 14, 15, 1, 61, 16]}

df_left = pd.DataFrame(raw_data, columns = ['subject_id', 'test_score'])

raw_data = {
    'subject_id': ['4', '5', '6', '7', '8'],
    'first_name': ['Billy', 'Brian', 'Bran', 'Bryce', 'Betty'],
    'last_name': ['Bonder', 'Black', 'Balwner', 'Brice', 'Btisan']}

df_right = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name'])

pd.merge(left=df_left, right=df_right, how="inner", on='subject_id')

# pd.merge(df_left, df_right, on='subject_id', how='left')

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_22.06.13.png

  • subject_id 를 기준으로 내부 조인을 수행
    • 키 값 subject_id 열의 값이 두 테이블 모두 존재해야 병합됨

연결

연결(concatenate)은 병합과는 달리 두 테이블을 그대로 붙이는 방법입니다.

데이터의 스키마가 동일할 때, 그대로 연결하며 주로 concat 함수를 사용합니다.

python
import os

print(os.getcwd())    # 현재 작업 디렉토리(현재 코드가 실행되는 폴더) 출력
print(os.listdir())   # 그 디렉토리에 있는 파일들과 폴더 목록 보기
python
import os

folder = '/content'
filenames = [
    os.path.join(folder, filename)
    for filename in os.listdir(folder)
    if 'sales' in filename and filename.endswith('.xlsx')
]

print(filenames)
#['/content/sales-jan.xlsx', '/content/sales-mar.xlsx', '/content/sales-feb.xlsx']

df_list = [pd.read_excel(filename, engine="openpyxl") for filename in filenames]
for df in df_list:
    print(type(df), len(df))
# <class 'pandas.core.frame.DataFrame'> 134
# <class 'pandas.core.frame.DataFrame'> 142
# <class 'pandas.core.frame.DataFrame'> 108

df = pd.concat(df_list, axis=0)
print(len(df)) # 384
df.reset_index(drop=True)

%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025-09-18_22.16.42.png