본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 16. · 8 Views
Pandas groupby 그룹별 분석 완벽 가이드
데이터를 그룹으로 나누어 통계를 내고 분석하는 방법을 배웁니다. groupby부터 agg, transform, apply까지 실무에서 자주 사용하는 그룹 분석 기법을 쉽게 설명합니다.
목차
1. groupby 기본 개념
어느 날 이슬 씨는 회사에서 매출 데이터를 분석하라는 업무를 받았습니다. 전국 지점별 매출을 비교해야 하는데, 데이터가 수천 건이나 됩니다.
"이걸 어떻게 정리하지?" 고민하던 이슬 씨에게 선배가 다가와 말했습니다. "groupby를 써보세요.
그룹별로 자동으로 계산해줘요."
**groupby()**는 데이터를 특정 기준으로 그룹을 나누고, 각 그룹에 대해 연산을 수행하는 기능입니다. 마치 학생들을 반별로 나누어 평균 점수를 계산하는 것과 같습니다.
이 기능을 사용하면 복잡한 반복문 없이도 그룹별 통계를 쉽게 계산할 수 있습니다.
다음 코드를 살펴봅시다.
import pandas as pd
# 매출 데이터 생성
sales_data = pd.DataFrame({
'지점': ['서울', '부산', '서울', '대구', '부산', '서울'],
'매출': [100, 80, 120, 90, 95, 110],
'직원수': [5, 3, 5, 4, 3, 5]
})
# 지점별로 그룹화하여 평균 매출 계산
result = sales_data.groupby('지점')['매출'].mean()
print(result)
# 출력: 서울 110.0, 부산 87.5, 대구 90.0
이슬 씨는 입사 2개월 차 데이터 분석가입니다. 오늘 팀장님께 전국 지점별 매출 현황을 정리하라는 업무를 받았습니다.
엑셀 파일을 열어보니 데이터가 수천 건이나 됩니다. 한 줄씩 보면서 지점별로 계산하려니 막막합니다.
선배 분석가 김데이터 씨가 모니터를 보더니 웃으며 말합니다. "아, 그거 groupby 쓰면 한 줄로 끝나요." 그렇다면 groupby란 정확히 무엇일까요?
쉽게 비유하자면, groupby는 마치 우편물을 지역별로 분류하는 것과 같습니다. 우체국 직원이 서울로 갈 편지, 부산으로 갈 편지를 각각 묶듯이, groupby도 데이터를 특정 기준으로 묶어줍니다.
그리고 묶인 각 그룹에 대해 원하는 계산을 수행할 수 있습니다. groupby가 없던 시절에는 어땠을까요?
개발자들은 반복문을 직접 작성해야 했습니다. 먼저 지점 목록을 뽑아내고, 각 지점별로 데이터를 필터링한 다음, 일일이 합계나 평균을 계산했습니다.
코드가 길어지고 실수하기도 쉬웠습니다. 더 큰 문제는 성능이었습니다.
데이터가 많아질수록 처리 속도가 급격히 느려졌습니다. 바로 이런 문제를 해결하기 위해 groupby가 등장했습니다.
groupby를 사용하면 한 줄로 그룹별 집계가 가능해집니다. 또한 내부적으로 최적화되어 있어 빠른 처리 속도를 자랑합니다.
무엇보다 코드가 직관적이어서 나중에 다시 봐도 쉽게 이해할 수 있다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 sales_data.groupby('지점') 부분을 보면 지점 컬럼을 기준으로 데이터를 그룹화한다는 의미입니다. 이 시점에 실제 계산은 아직 일어나지 않습니다.
다음으로 **['매출']**을 통해 매출 컬럼만 선택합니다. 마지막으로 **mean()**을 호출하면 각 그룹의 평균이 계산되어 반환됩니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 전자상거래 회사에서 일한다고 가정해봅시다.
상품 카테고리별 평균 판매가를 알고 싶을 때 groupby를 활용하면 즉시 결과를 얻을 수 있습니다. 네이버, 쿠팡 같은 대형 플랫폼에서도 이런 패턴으로 수많은 데이터를 분석하고 있습니다.
하지만 주의할 점도 있습니다. 초보 분석가들이 흔히 하는 실수 중 하나는 그룹화 기준 컬럼에 결측값이 있을 때입니다.
결측값이 있으면 해당 행은 기본적으로 그룹에서 제외됩니다. 따라서 데이터를 미리 확인하고 결측값을 처리해야 합니다.
다시 이슬 씨의 이야기로 돌아가 봅시다. 김데이터 씨의 설명을 들은 이슬 씨는 감탄했습니다.
"이렇게 간단한 거였네요!" groupby를 제대로 이해하면 데이터 분석 업무가 훨씬 빨라지고 효율적으로 바뀝니다. 여러분도 오늘 배운 내용을 실제 데이터에 적용해 보세요.
실전 팁
💡 - groupby() 만으로는 계산이 일어나지 않습니다. 반드시 sum(), mean() 같은 집계 함수를 붙여야 합니다.
- 그룹화 결과는 기본적으로 인덱스가 됩니다. **reset_index()**를 사용하면 일반 컬럼으로 변환할 수 있습니다.
2. 단일 컬럼 그룹화
이슬 씨가 groupby의 기본을 익히고 나니, 팀장님이 새로운 요청을 하셨습니다. "이번엔 월별 매출도 분석해주세요." 날짜 데이터를 어떻게 그룹화할지 고민하던 이슬 씨는 선배에게 다시 물어봤습니다.
"날짜 컬럼도 groupby로 할 수 있나요?"
단일 컬럼 그룹화는 하나의 컬럼만을 기준으로 데이터를 나누는 방법입니다. 가장 기본적이면서도 실무에서 가장 많이 사용하는 패턴입니다.
날짜, 카테고리, 지역 등 어떤 컬럼이든 기준으로 삼을 수 있으며, 다양한 집계 함수를 적용할 수 있습니다.
다음 코드를 살펴봅시다.
import pandas as pd
import numpy as np
# 날짜별 매출 데이터
df = pd.DataFrame({
'날짜': pd.date_range('2024-01-01', periods=12, freq='M'),
'매출': [100, 120, 110, 130, 150, 140, 160, 155, 170, 180, 165, 190],
'비용': [60, 70, 65, 75, 85, 80, 90, 88, 95, 100, 92, 105]
})
# 월을 추출하여 그룹화
df['월'] = df['날짜'].dt.month
분기별 = df.groupby(df['날짜'].dt.quarter)['매출'].sum()
print(f"분기별 매출:\n{분기별}")
이슬 씨는 이제 groupby의 기본 개념을 이해했습니다. 하지만 실무는 더 복잡합니다.
팀장님이 월별 매출 분석뿐 아니라 분기별 매출도 보고 싶다고 하셨습니다. 김데이터 씨가 말합니다.
"날짜 데이터는 좀 특별해요. 원하는 단위로 자유롭게 그룹화할 수 있거든요." 단일 컬럼 그룹화는 가장 기본적인 그룹화 방법입니다.
비유하자면, 학생들을 학년별로 나누는 것과 같습니다. 1학년끼리, 2학년끼리, 3학년끼리 묶어서 각 학년의 평균 키를 계산하는 것처럼 말입니다.
하나의 명확한 기준으로 전체를 여러 그룹으로 분류하는 것이 핵심입니다. 왜 단일 컬럼 그룹화가 중요할까요?
데이터 분석의 첫 단계는 대부분 하나의 기준으로 데이터를 요약하는 것입니다. 매출 데이터를 지점별로 보거나, 고객 데이터를 연령대별로 보는 것이 전형적인 예입니다.
이런 분석 없이는 데이터의 전체적인 패턴을 파악하기 어렵습니다. 단일 컬럼 그룹화를 마스터하면 대부분의 기본 분석을 수행할 수 있습니다.
날짜 컬럼의 경우 특히 유용합니다. dt.quarter를 사용하면 분기별로, dt.month를 사용하면 월별로, dt.dayofweek를 사용하면 요일별로 그룹화할 수 있습니다.
이렇게 같은 날짜 데이터로도 다양한 관점의 분석이 가능합니다. 위의 코드를 자세히 살펴보겠습니다.
먼저 **pd.date_range()**로 월별 날짜 데이터를 생성했습니다. 그 다음 df['날짜'].dt.quarter를 사용하여 각 날짜가 몇 분기인지 추출합니다.
13월은 1분기, 46월은 2분기가 되는 식입니다. 마지막으로 **sum()**을 호출하면 각 분기별 매출 합계가 계산됩니다.
실제 현업에서는 어떻게 쓰일까요? 예를 들어 마케팅팀에서 광고 효과를 분석한다고 생각해봅시다.
광고 채널별로 클릭 수를 그룹화하면, 어느 채널이 가장 효과적인지 한눈에 볼 수 있습니다. 네이버 광고가 1000건, 구글 광고가 800건, 페이스북 광고가 1200건처럼 말입니다.
또 다른 예로 제조업에서는 불량률을 라인별로 분석합니다. A라인, B라인, C라인 각각의 불량 개수를 계산하여, 어느 라인에 문제가 있는지 파악할 수 있습니다.
주의해야 할 점도 있습니다. 그룹화 기준 컬럼에 데이터 타입이 섞여 있으면 오류가 발생할 수 있습니다.
예를 들어 숫자와 문자가 섞여 있는 경우입니다. 따라서 df['컬럼'].dtype으로 미리 데이터 타입을 확인하는 습관을 들이세요.
다시 이슬 씨의 상황으로 돌아갑시다. 김데이터 씨의 도움으로 이슬 씨는 분기별 매출 보고서를 깔끔하게 작성했습니다.
팀장님이 칭찬까지 해주셨습니다. 단일 컬럼 그룹화는 간단하지만 강력합니다.
이 기법만 제대로 익혀도 데이터 분석의 절반은 해결할 수 있습니다.
실전 팁
💡 - 날짜 컬럼은 dt accessor를 활용하면 다양하게 그룹화할 수 있습니다 (year, month, quarter, dayofweek 등).
- **value_counts()**는 groupby().count()의 간편 버전입니다. 빈도를 빠르게 확인할 때 유용합니다.
3. 여러 컬럼 그룹화
며칠 후, 팀장님이 더 구체적인 요청을 하셨습니다. "이번엔 지점별, 제품 카테고리별로 교차 분석을 해주세요." 이슬 씨는 당황했습니다.
지금까지는 하나의 기준으로만 그룹화했는데, 두 개를 동시에 할 수 있을까요?
여러 컬럼 그룹화는 두 개 이상의 컬럼을 동시에 기준으로 삼아 데이터를 나누는 방법입니다. 마치 학생들을 학년별, 반별로 동시에 나누는 것과 같습니다.
이를 통해 더 세밀한 분석이 가능하며, 교차 집계 형태의 결과를 얻을 수 있습니다.
다음 코드를 살펴봅시다.
import pandas as pd
# 지점별, 카테고리별 매출 데이터
sales_df = pd.DataFrame({
'지점': ['서울', '서울', '부산', '부산', '서울', '부산'],
'카테고리': ['전자', '의류', '전자', '의류', '전자', '전자'],
'매출': [200, 150, 180, 120, 220, 190],
'수량': [10, 15, 9, 12, 11, 10]
})
# 지점과 카테고리로 동시 그룹화
result = sales_df.groupby(['지점', '카테고리']).agg({
'매출': 'sum',
'수량': 'sum'
})
print(result)
이슬 씨는 팀장님의 새로운 요청에 잠시 멈칫했습니다. 지점별 분석은 할 줄 알지만, 지점별이면서 동시에 카테고리별 분석을 하려면 어떻게 해야 할까요?
김데이터 씨가 커피를 한 잔 건네며 말합니다. "걱정 마세요.
groupby에 리스트를 넘기면 돼요." 여러 컬럼 그룹화란 무엇일까요? 쉽게 비유하면, 책을 정리하는 방법과 같습니다.
먼저 장르별로 나누고, 그 안에서 다시 저자별로 나눕니다. 소설 중에서도 김작가의 책, 이작가의 책으로 세분화하는 것입니다.
이렇게 두 단계 이상의 기준으로 분류하면 훨씬 구체적인 정보를 얻을 수 있습니다. 왜 여러 컬럼으로 그룹화해야 할까요?
실무에서는 하나의 기준만으로는 부족한 경우가 많습니다. 예를 들어 서울 지점의 매출이 높다고 해서 모든 제품이 잘 팔리는 것은 아닙니다.
어쩌면 전자제품만 잘 팔리고 의류는 부산 지점이 더 나을 수도 있습니다. 이런 숨겨진 패턴을 발견하려면 교차 분석이 필수입니다.
여러 컬럼 그룹화를 사용하면 이런 복잡한 분석도 간단해집니다. groupby에 컬럼 이름을 리스트로 전달하면 됩니다.
**groupby(['지점', '카테고리'])**처럼 말입니다. 그러면 먼저 지점별로 나누고, 각 지점 내에서 다시 카테고리별로 나눕니다.
결과는 MultiIndex 형태로 반환되어 계층적 구조를 갖습니다. 코드를 단계별로 분석해보겠습니다.
**groupby(['지점', '카테고리'])**는 두 컬럼을 기준으로 그룹을 만듭니다. 서울-전자, 서울-의류, 부산-전자, 부산-의류처럼 가능한 모든 조합이 그룹이 됩니다.
다음으로 agg() 함수를 사용하면 컬럼별로 다른 집계 함수를 적용할 수 있습니다. 매출은 합계를, 수량도 합계를 계산하도록 지정했습니다.
실무에서는 이런 식으로 활용됩니다. 쇼핑몰 데이터를 분석한다면 연령대별, 성별로 그룹화하여 어떤 고객층이 어떤 제품을 선호하는지 파악할 수 있습니다.
20대 여성은 화장품을, 30대 남성은 전자기기를 많이 산다는 식의 인사이트를 얻는 것입니다. 제조 현장에서는 날짜별, 라인별로 그룹화하여 특정 날짜에 특정 라인에서 불량이 집중됐는지 분석합니다.
이런 분석으로 문제의 원인을 빠르게 찾아낼 수 있습니다. 주의할 점이 있습니다.
그룹 개수가 너무 많아지면 결과를 해석하기 어려워집니다. 예를 들어 10개 지점에 20개 카테고리면 최대 200개 그룹이 생깁니다.
이럴 땐 주요 그룹만 선택하거나, 피벗 테이블 형태로 변환하는 것이 좋습니다. 이슬 씨는 여러 컬럼 그룹화로 교차 분석 보고서를 완성했습니다.
팀장님은 결과를 보시더니 만족스러운 표정을 지으셨습니다. "이제 어느 지점에 어떤 제품을 더 공급해야 할지 알겠네요." 여러 컬럼 그룹화는 데이터의 숨은 패턴을 발견하는 열쇠입니다.
복잡해 보이지만, 한 번 익히면 강력한 무기가 됩니다.
실전 팁
💡 - MultiIndex 결과가 불편하다면 **reset_index()**로 평평하게 만들 수 있습니다.
- 세 개 이상의 컬럼도 그룹화할 수 있지만, 너무 많으면 해석이 어려우니 보통 2-3개가 적당합니다.
4. agg로 여러 통계 계산
이슬 씨가 점점 익숙해지자, 팀장님의 요구사항도 복잡해졌습니다. "매출은 합계를, 수량은 평균을, 그리고 거래 건수도 같이 보고 싶어요." 이슬 씨는 당황했습니다.
각각 따로 계산해야 하나요?
agg() 함수는 한 번에 여러 가지 집계 함수를 적용할 수 있는 강력한 도구입니다. 컬럼마다 다른 집계 방식을 지정할 수 있고, 하나의 컬럼에 여러 통계를 동시에 계산할 수도 있습니다.
이를 통해 복잡한 분석을 간결한 코드로 수행할 수 있습니다.
다음 코드를 살펴봅시다.
import pandas as pd
import numpy as np
# 상세한 거래 데이터
transactions = pd.DataFrame({
'지점': ['서울', '서울', '부산', '서울', '부산', '부산'],
'매출': [100, 150, 120, 130, 110, 140],
'수량': [5, 8, 6, 7, 5, 9],
'할인율': [10, 5, 15, 10, 20, 5]
})
# 여러 통계를 한번에 계산
result = transactions.groupby('지점').agg({
'매출': ['sum', 'mean', 'max'], # 매출은 합계, 평균, 최대값
'수량': ['mean', 'std'], # 수량은 평균, 표준편차
'할인율': 'mean' # 할인율은 평균
})
print(result)
이슬 씨는 이제 groupby의 기본을 넘어 중급 단계로 접어들었습니다. 하지만 팀장님의 요구사항은 점점 구체적이고 복잡해집니다.
김데이터 씨가 이슬 씨의 화면을 보더니 말합니다. "아, 이럴 때 agg 함수를 쓰면 한 번에 해결돼요." agg() 함수는 무엇일까요?
비유하자면, agg는 만능 계산기와 같습니다. 일반 계산기는 한 번에 하나의 계산만 하지만, 만능 계산기는 더하기, 빼기, 곱하기를 동시에 보여줍니다.
agg도 마찬가지로 합계, 평균, 최대값을 한 번에 계산해줍니다. 왜 agg가 필요할까요?
실무에서는 하나의 통계만으로는 부족합니다. 매출 데이터를 분석할 때 합계만 보면 전체 규모를 알 수 있지만, 평균을 봐야 거래당 금액을 알 수 있습니다.
최대값을 보면 가장 큰 거래가 얼마인지 파악할 수 있습니다. 이 모든 것을 따로따로 계산하면 코드가 길어지고 비효율적입니다.
agg() 함수를 사용하면 이런 반복 작업을 한 번에 처리할 수 있습니다. 사전 형태로 컬럼별 집계 방식을 지정하면 됩니다.
리스트로 여러 함수를 전달하면 하나의 컬럼에 여러 통계가 적용됩니다. 판다스가 자동으로 모든 계산을 수행하고 깔끔한 표 형태로 결과를 보여줍니다.
코드를 자세히 뜯어보겠습니다. agg() 함수에 사전을 전달했습니다.
키는 컬럼 이름이고, 값은 적용할 함수입니다. **'매출': ['sum', 'mean', 'max']**는 매출 컬럼에 세 가지 함수를 적용하라는 의미입니다.
결과는 MultiIndex columns 형태가 됩니다. 첫 번째 레벨은 컬럼 이름, 두 번째 레벨은 함수 이름입니다.
실제 업무에서는 어떻게 쓰일까요? 고객 서비스팀에서 CS 처리 시간을 분석한다면, 평균 처리 시간과 최대 처리 시간을 동시에 봐야 합니다.
평균은 전반적인 효율성을, 최대값은 최악의 케이스를 알려줍니다. 이 두 가지를 함께 보면 서비스 품질을 종합적으로 평가할 수 있습니다.
영업팀에서는 영업사원별 실적을 분석할 때 합계로 총 매출을, 평균으로 건당 매출을, count로 거래 횟수를 한 번에 계산합니다. 이를 통해 누가 큰 거래를 따내는지, 누가 부지런히 발로 뛰는지 알 수 있습니다.
몇 가지 주의사항이 있습니다. 함수 이름을 문자열로 전달할 수도 있고, 실제 함수 객체를 전달할 수도 있습니다.
'sum' 대신 np.sum을 써도 됩니다. 하지만 문자열이 더 간결하고 가독성이 좋습니다.
또한 결과의 컬럼 이름이 튜플 형태로 나오는데, 이게 불편하다면 columns 속성을 수정하거나 rename을 사용하여 평평하게 만들 수 있습니다. 이슬 씨는 agg 함수로 한 번에 여러 통계를 계산하여 보고서를 완성했습니다.
팀장님이 보시더니 놀라워하셨습니다. "이렇게 빨리 끝낼 수 있었어요?" agg 함수는 복잡한 집계 작업을 단순하게 만들어줍니다.
한 번 배워두면 분석 속도가 크게 향상됩니다.
실전 팁
💡 - 기본 제공 함수 외에 numpy 함수도 사용할 수 있습니다 (np.median, np.std 등).
- 컬럼 이름을 바꾸고 싶다면 agg(새이름=('컬럼', '함수')) 형태로 named aggregation을 사용하세요.
5. 사용자 정의 집계 함수
어느 날 이슬 씨는 특별한 요청을 받았습니다. "최대값과 최소값의 차이를 계산해주세요." 그런데 판다스에는 그런 함수가 없었습니다.
이슬 씨는 난감해졌습니다. 직접 함수를 만들어야 하나요?
사용자 정의 집계 함수는 판다스가 기본 제공하지 않는 계산을 수행할 때 사용합니다. 직접 함수를 작성하여 agg()에 전달하면, groupby된 각 그룹에 그 함수가 적용됩니다.
이를 통해 무한히 확장 가능한 분석이 가능해집니다.
다음 코드를 살펴봅시다.
import pandas as pd
# 매출 데이터
sales = pd.DataFrame({
'지점': ['서울', '서울', '부산', '서울', '부산', '부산'],
'매출': [100, 150, 120, 130, 110, 140]
})
# 사용자 정의 함수: 범위(최대-최소)
def calculate_range(series):
return series.max() - series.min()
# 사용자 정의 함수: 변동계수(CV)
def coefficient_of_variation(series):
return series.std() / series.mean() * 100
# 사용자 정의 함수 적용
result = sales.groupby('지점')['매출'].agg([
'mean',
('범위', calculate_range),
('변동계수', coefficient_of_variation)
])
print(result)
이슬 씨는 이제 groupby와 agg를 능숙하게 다룰 수 있게 되었습니다. 그런데 이번 요청은 조금 다릅니다.
판다스 매뉴얼을 아무리 뒤져봐도 "최대값과 최소값의 차이"를 계산하는 함수는 없습니다. 김데이터 씨가 웃으며 말합니다.
"그럴 땐 직접 만들면 돼요. 파이썬이잖아요." 사용자 정의 집계 함수란 무엇일까요?
비유하자면, 레고 블록과 같습니다. 기본 세트에 있는 블록만으로도 많은 걸 만들 수 있지만, 때로는 특수한 모양의 블록이 필요합니다.
그럴 땐 직접 만들면 됩니다. 판다스도 마찬가지로 기본 함수가 풍부하지만, 특수한 계산이 필요하면 직접 함수를 작성하면 됩니다.
왜 사용자 정의 함수가 필요할까요? 통계학이나 비즈니스 분석에는 수많은 지표가 있습니다.
판다스가 모든 것을 제공할 수는 없습니다. 예를 들어 변동계수(coefficient of variation)는 표준편차를 평균으로 나눈 값인데, 이런 건 직접 계산해야 합니다.
회사마다 독자적인 KPI를 사용하는 경우도 많습니다. 사용자 정의 집계 함수를 사용하면 어떤 계산이든 가능해집니다.
방법은 간단합니다. 시리즈를 입력받아 숫자를 반환하는 함수를 작성하면 됩니다.
그리고 그 함수를 agg()에 전달하면 끝입니다. 판다스가 각 그룹의 데이터를 함수에 넘겨주고, 결과를 모아서 표로 만들어줍니다.
코드를 한 줄씩 살펴보겠습니다. calculate_range 함수는 시리즈를 받아서 최대값과 최소값의 차이를 반환합니다.
coefficient_of_variation 함수는 표준편차를 평균으로 나눈 뒤 100을 곱해 퍼센트로 표현합니다. 이 함수들을 agg() 에 리스트로 전달하면 됩니다.
튜플 형태로 **(이름, 함수)**를 전달하면 결과 컬럼 이름을 지정할 수 있습니다. 실무에서는 어떻게 활용될까요?
금융권에서는 샤프 비율, 최대 손실률 같은 복잡한 지표를 계산합니다. 이런 건 표준 함수로는 불가능하고 직접 구현해야 합니다.
제조업에서는 공정 능력 지수(Cpk) 같은 품질 지표를 계산하는데, 이것도 사용자 정의 함수로 구현합니다. 마케팅 분야에서는 고객별 RFM 점수(최근성, 빈도, 금액)를 계산할 때 회사마다 다른 공식을 사용합니다.
이런 독자적인 로직은 사용자 정의 함수로만 구현할 수 있습니다. 주의할 점이 몇 가지 있습니다.
사용자 정의 함수는 내장 함수보다 느립니다. 판다스의 내장 함수는 C로 구현되어 최적화되어 있지만, 사용자 함수는 파이썬으로 실행됩니다.
따라서 데이터가 아주 많다면 성능을 고려해야 합니다. 또한 함수 안에서 오류가 나지 않도록 예외 처리를 신경 써야 합니다.
빈 그룹이나 결측값이 있을 때도 안전하게 동작해야 합니다. 이슬 씨는 사용자 정의 함수로 팀장님이 원하는 독특한 지표를 계산해냈습니다.
팀장님이 감탄하며 말씀하셨습니다. "우리 회사만의 분석 방식을 코드로 구현할 수 있다니 대단하네요!" 사용자 정의 집계 함수는 판다스를 진정으로 자유롭게 사용하게 해주는 열쇠입니다.
상상하는 모든 분석이 가능해집니다.
실전 팁
💡 - lambda 함수를 사용하면 간단한 계산은 한 줄로 작성할 수 있습니다. 예: lambda x: x.max() - x.min()
- 함수 안에서 **len(series)**로 그룹의 크기를 확인하고, 너무 작으면 None을 반환하는 식으로 방어적 코드를 작성하세요.
6. transform과 apply
이슬 씨가 분석에 자신감이 붙자, 새로운 문제가 생겼습니다. "각 매출을 지점별 평균으로 나눈 값을 원본 데이터에 추가해주세요." 집계가 아니라 변환이 필요한 상황입니다.
이슬 씨는 어떻게 해야 할지 고민에 빠졌습니다.
**transform()**은 집계가 아닌 변환을 수행하며, 원본 데이터와 같은 크기의 결과를 반환합니다. **apply()**는 더 유연하여 시리즈나 데이터프레임을 반환할 수 있습니다.
이 두 함수는 그룹별 계산 결과를 원본 데이터에 다시 결합할 때 매우 유용합니다.
다음 코드를 살펴봅시다.
import pandas as pd
# 직원별 매출 데이터
employee_sales = pd.DataFrame({
'지점': ['서울', '서울', '부산', '부산', '서울', '부산'],
'직원': ['김철수', '이영희', '박민수', '최지은', '정다은', '강호준'],
'매출': [100, 150, 120, 90, 130, 140]
})
# transform: 그룹 평균을 각 행에 매핑
employee_sales['지점평균'] = employee_sales.groupby('지점')['매출'].transform('mean')
# 평균 대비 비율 계산
employee_sales['평균대비'] = (employee_sales['매출'] / employee_sales['지점평균'] * 100).round(1)
# apply: 그룹별 상위 2명 선택
top_performers = employee_sales.groupby('지점').apply(
lambda x: x.nlargest(2, '매출')
).reset_index(drop=True)
print("Transform 결과:\n", employee_sales)
print("\nApply 결과:\n", top_performers)
이슬 씨는 이제 groupby의 고급 단계로 진입했습니다. 지금까지는 그룹별로 하나의 값을 계산하는 집계를 해왔습니다.
하지만 이번엔 다릅니다. 각 직원의 매출을 지점 평균과 비교하려면, 집계 결과를 다시 원본 데이터에 붙여야 합니다.
김데이터 씨가 설명합니다. "이럴 땐 transform을 쓰세요.
마법 같은 기능이에요." **transform()**과 **apply()**는 무엇이 다를까요? 비유하자면, transform은 복사-붙여넣기와 같습니다.
그룹별 평균을 계산한 뒤, 그 평균값을 각 그룹의 모든 행에 복사합니다. 반면 apply는 범용 도구로, 그룹마다 원하는 어떤 작업이든 수행할 수 있습니다.
필터링, 정렬, 선택 등 무엇이든 가능합니다. 왜 transform과 apply가 필요할까요?
실무에서는 집계 결과를 원본과 비교해야 하는 경우가 많습니다. 각 직원의 매출이 지점 평균보다 높은지 낮은지 알아야 성과를 평가할 수 있습니다.
이럴 때 집계 결과를 별도로 계산한 뒤 merge로 합치면 코드가 복잡해집니다. transform을 사용하면 한 줄로 해결됩니다.
**transform()**의 핵심 특징은 결과의 크기입니다. 일반 집계는 그룹당 하나의 값을 반환합니다.
서울 지점이 3명이라도 평균은 하나입니다. 하지만 transform은 원본과 같은 크기를 유지합니다.
서울 지점 3명 모두에게 같은 평균값을 할당합니다. 이렇게 되면 원본 데이터프레임에 바로 컬럼으로 추가할 수 있습니다.
코드를 단계별로 분석해보겠습니다. **groupby('지점')['매출'].transform('mean')**은 지점별 평균을 계산하되, 각 행에 해당 지점의 평균을 반환합니다.
서울 지점 직원들은 모두 서울 평균을 받고, 부산 지점 직원들은 모두 부산 평균을 받습니다. 그 다음 평균대비 컬럼을 계산하여 각 직원이 평균 대비 몇 퍼센트인지 알 수 있습니다.
apply() 함수는 더 강력합니다. 각 그룹에 대해 임의의 함수를 실행할 수 있습니다.
위 코드에서는 **nlargest()**를 사용하여 그룹별 상위 2명을 선택했습니다. apply는 시리즈가 아니라 데이터프레임을 반환할 수도 있어서, 복잡한 로직을 구현하기에 적합합니다.
실무 활용 사례를 살펴보겠습니다. HR 부서에서 직원 평가를 할 때, 부서별 평균 점수를 기준으로 상대 평가를 합니다.
이때 transform으로 부서 평균을 각 직원 행에 추가하고, 개인 점수와 비교합니다. 평균보다 높으면 A등급, 낮으면 B등급 같은 식입니다.
영업팀에서는 월별 매출 추이를 분석할 때, 이동평균을 계산합니다. 직전 3개월 평균을 각 월에 할당하려면 transform을 사용합니다.
이렇게 하면 트렌드를 한눈에 볼 수 있습니다. 주의할 점도 있습니다.
apply는 매우 유연하지만 느립니다. 각 그룹마다 파이썬 함수를 호출하기 때문입니다.
데이터가 크면 시간이 오래 걸립니다. 가능하면 transform이나 agg 같은 최적화된 함수를 먼저 고려하세요.
또한 apply의 결과가 MultiIndex를 가질 수 있어서, **reset_index(drop=True)**로 정리해야 하는 경우가 많습니다. 이슬 씨는 transform과 apply를 활용하여 직원별 성과를 지점 평균과 비교하는 보고서를 만들었습니다.
팀장님이 보시더니 칭찬하셨습니다. "이제 누가 우수 사원인지 명확하네요!" transform과 apply는 groupby의 진정한 힘을 발휘하게 해주는 고급 도구입니다.
이 두 가지를 마스터하면 거의 모든 그룹별 분석을 수행할 수 있습니다.
실전 팁
💡 - **transform()**에는 'mean', 'sum' 같은 문자열뿐 아니라 사용자 정의 함수도 전달할 수 있습니다.
- **apply()**는 병렬 처리가 안 되므로, 대용량 데이터에는 다른 방법을 고려하세요 (벡터화 연산 등).
7. 그룹별 결과 시각화
며칠간의 분석 작업 끝에, 팀장님이 마지막 요청을 하셨습니다. "수치만 보면 이해하기 어려워요.
그래프로 보여주세요." 이슬 씨는 지금까지 숫자만 다뤘지, 시각화는 해본 적이 없었습니다. 어떻게 해야 할까요?
그룹별 결과 시각화는 집계된 데이터를 막대 그래프, 선 그래프 등으로 표현하는 방법입니다. 판다스는 matplotlib과 통합되어 있어 plot() 메서드로 간편하게 시각화할 수 있습니다.
시각화를 통해 패턴과 트렌드를 직관적으로 파악할 수 있습니다.
다음 코드를 살펴봅시다.
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.family'] = 'Malgun Gothic' # 한글 폰트 설정
matplotlib.rcParams['axes.unicode_minus'] = False # 마이너스 기호 깨짐 방지
# 월별 지점별 매출 데이터
monthly_sales = pd.DataFrame({
'월': [1, 1, 2, 2, 3, 3, 1, 2, 3] * 2,
'지점': ['서울']*9 + ['부산']*9,
'매출': [100, 120, 150, 140, 160, 170, 90, 100, 110, 95, 105, 115, 85, 92, 100]
})
# 그룹별 집계
grouped = monthly_sales.groupby(['월', '지점'])['매출'].sum().unstack()
# 막대 그래프
grouped.plot(kind='bar', title='월별 지점별 매출', figsize=(10, 6))
plt.ylabel('매출 (만원)')
plt.xlabel('월')
plt.legend(title='지점')
plt.tight_layout()
plt.show()
이슬 씨는 지금까지 완벽한 분석을 해왔습니다. 하지만 숫자로 가득한 표를 보면서 팀장님은 고개를 갸우뚱하셨습니다.
"음... 숫자는 많은데 한눈에 안 들어오네요." 김데이터 씨가 조언합니다.
"사람은 시각적 동물이에요. 그래프로 보여주면 훨씬 이해하기 쉽죠." 그룹별 결과 시각화는 왜 중요할까요?
비유하자면, 지도와 같습니다. 좌표를 숫자로 나열하면 정확하지만 위치를 파악하기 어렵습니다.
지도로 보면 한눈에 전체 구조를 이해할 수 있습니다. 데이터 분석도 마찬가지입니다.
표로는 정확한 값을 알 수 있지만, 그래프로는 패턴과 추세를 즉시 파악할 수 있습니다. 왜 groupby 결과를 시각화해야 할까요?
실무에서 분석 결과는 결국 의사결정권자에게 보고됩니다. 임원진이나 고객은 통계학을 모를 수 있습니다.
하지만 그래프는 누구나 이해할 수 있습니다. 서울 지점이 부산보다 높다는 것을 막대 그래프로 보면 3초 만에 파악됩니다.
판다스는 시각화를 매우 쉽게 만들어줍니다. plot() 메서드만 호출하면 자동으로 그래프가 그려집니다.
내부적으로 matplotlib을 사용하지만, 복잡한 설정 없이 간단한 코드만으로 시각화가 가능합니다. kind 매개변수로 그래프 종류를 선택할 수 있습니다.
막대 그래프는 'bar', 선 그래프는 'line', 파이 차트는 'pie'입니다. 코드를 단계별로 살펴보겠습니다.
먼저 한글이 깨지지 않도록 matplotlib 폰트를 설정했습니다. 다음으로 **groupby(['월', '지점'])**로 월별, 지점별 매출을 집계했습니다.
**unstack()**을 호출하면 피벗 테이블 형태로 변환되어 지점이 컬럼이 됩니다. 이제 **plot(kind='bar')**로 막대 그래프를 그립니다.
각 월마다 지점별 막대가 나란히 표시됩니다. figsize로 그래프 크기를 조정하고, ylabel, xlabel로 축 레이블을 추가했습니다.
**legend()**로 범례를 표시하여 어느 색이 어느 지점인지 알 수 있게 했습니다. 실무에서는 어떤 그래프를 쓸까요?
막대 그래프는 범주형 데이터 비교에 적합합니다. 지점별, 제품별 매출을 비교할 때 사용합니다.
선 그래프는 시계열 데이터에 적합합니다. 월별, 분기별 추이를 볼 때 선 그래프로 그리면 트렌드가 명확하게 보입니다.
파이 차트는 비율을 보여줄 때 좋습니다. 전체 매출 중 각 지점이 차지하는 비중을 한눈에 볼 수 있습니다.
단, 항목이 많으면 읽기 어려우니 5개 이하일 때 사용하세요. 상자 그림(boxplot)은 분포를 보여줍니다.
그룹별 매출의 중앙값, 사분위수, 이상치를 한 번에 파악할 수 있어 통계 분석에 유용합니다. 몇 가지 팁을 드리겠습니다.
그래프에 제목과 레이블을 반드시 추가하세요. 그래프만 보고도 무엇을 나타내는지 알 수 있어야 합니다.
색상도 신경 쓰세요. 너무 많은 색을 쓰면 혼란스럽고, 색맹인 사람도 구분할 수 있도록 배려해야 합니다.
데이터가 많으면 그래프가 복잡해집니다. 이럴 땐 상위 N개만 선택하거나, 서브플롯으로 나누어 그리는 것이 좋습니다.
이슬 씨는 그래프까지 포함된 보고서를 완성했습니다. 팀장님이 보시더니 환한 미소를 지으셨습니다.
"이제 완벽하네요! 한눈에 이해가 됩니다." 데이터 분석의 마지막 단계는 결국 커뮤니케이션입니다.
아무리 훌륭한 분석도 전달되지 않으면 의미가 없습니다. 시각화는 분석 결과를 효과적으로 전달하는 가장 강력한 도구입니다.
이슬 씨는 이제 groupby의 기초부터 고급 활용, 시각화까지 모두 마스터했습니다. 팀에서 없어서는 안 될 분석 전문가가 되었습니다.
여러분도 오늘 배운 내용을 실제 업무에 적용해 보세요. 처음엔 어려울 수 있지만, 하나씩 연습하다 보면 어느새 groupby의 달인이 되어 있을 것입니다.
실전 팁
💡 - seaborn 라이브러리를 사용하면 더 예쁜 그래프를 그릴 수 있습니다. **sns.barplot()**을 시도해보세요.
- 대시보드를 만들려면 plotly 라이브러리로 인터랙티브 그래프를 만들 수 있습니다. 마우스를 올리면 값이 보이는 식입니다.
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.