🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

다중 조건 분석 완벽 가이드 - 슬라이드 1/8
A

AI Generated

2025. 12. 17. · 7 Views

다중 조건 분석 완벽 가이드

복잡한 데이터에서 여러 조건으로 필터링하고, 교차표와 피벗 테이블로 인사이트를 도출하는 방법을 배웁니다. 초급 개발자도 쉽게 따라할 수 있는 실무 중심의 데이터 분석 가이드입니다.


목차

  1. 다중 조건 필터링
  2. crosstab으로 교차표 생성
  3. pivot_table 기본 사용법
  4. 여러 집계 함수 적용
  5. 피벗 결과 시각화
  6. melt로 데이터 변환
  7. 분석 인사이트 도출

1. 다중 조건 필터링

어느 날 김개발 씨는 회사의 판매 데이터를 분석하는 임무를 받았습니다. "이번 달 서울 지역에서 10만원 이상 구매한 고객 목록을 뽑아주세요." 선배는 간단히 말했지만, 김개발 씨는 어디서부터 시작해야 할지 막막했습니다.

다중 조건 필터링은 데이터에서 여러 조건을 동시에 만족하는 행만 추출하는 작업입니다. 마치 도서관에서 "컴퓨터 분야이면서 2020년 이후 출판된 책"을 찾는 것과 같습니다.

Pandas에서는 &(AND), |(OR) 연산자로 조건을 조합하며, 각 조건은 반드시 괄호로 감싸야 합니다.

다음 코드를 살펴봅시다.

import pandas as pd

# 샘플 데이터 생성
df = pd.DataFrame({
    '지역': ['서울', '부산', '서울', '대구', '서울'],
    '구매금액': [120000, 80000, 150000, 90000, 200000],
    '회원등급': ['VIP', '일반', 'VIP', '일반', 'VVIP']
})

# 다중 조건 필터링: 서울 지역이면서 10만원 이상 구매
filtered = df[(df['지역'] == '서울') & (df['구매금액'] >= 100000)]
print(filtered)

김개발 씨는 데이터 분석 업무를 시작한 지 2주 된 신입 개발자입니다. 오늘 아침, 팀장님으로부터 급한 요청을 받았습니다.

"김 대리, 이번 분기 마케팅 캠페인 대상자 리스트 좀 뽑아줄래요?" 요구사항은 명확했습니다. 서울 지역 고객 중에서 구매금액이 10만원 이상인 사람들만 선별하면 됩니다.

하지만 막상 코드를 작성하려니 막막했습니다. 그렇다면 다중 조건 필터링이란 정확히 무엇일까요?

쉽게 비유하자면, 다중 조건 필터링은 마치 채용 공고의 자격요건과 같습니다. "경력 3년 이상, 학사 학위 소지자"라는 조건이 있다면, 두 조건을 모두 만족하는 지원자만 서류 통과가 되는 것처럼 말이죠.

데이터 분석에서도 마찬가지로 여러 기준을 동시에 적용해서 원하는 데이터만 추출해냅니다. 다중 조건 필터링이 없던 시절에는 어땠을까요?

개발자들은 먼저 한 조건으로 필터링한 결과를 변수에 저장하고, 그 결과에 다시 두 번째 조건을 적용하는 방식으로 작업했습니다. 코드가 길어지고, 중간 변수도 많이 생기다 보니 실수하기 쉬웠습니다.

더 큰 문제는 가독성이었습니다. 조건이 3개, 4개로 늘어나면 코드를 이해하기가 매우 어려워졌습니다.

바로 이런 문제를 해결하기 위해 논리 연산자를 활용한 다중 조건 필터링이 등장했습니다. Pandas에서는 &(AND), |(OR), ~(NOT) 연산자로 여러 조건을 한 번에 표현할 수 있습니다.

코드가 간결해지고, 의도가 명확히 드러나는 장점이 있습니다. 무엇보다 한 줄로 복잡한 조건을 표현할 수 있다는 큰 이점이 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 DataFrame을 생성하는 부분입니다.

지역, 구매금액, 회원등급 세 개의 컬럼으로 구성된 간단한 샘플 데이터입니다. 핵심은 filtered = df[(df['지역'] == '서울') & (df['구매금액'] >= 100000)] 이 부분입니다.

여기서 각 조건을 괄호로 감싸는 것이 중요합니다. 괄호가 없으면 연산자 우선순위 때문에 오류가 발생합니다.

df['지역'] == '서울'은 불리언(True/False) 시리즈를 반환합니다. 마찬가지로 df['구매금액'] >= 100000도 불리언 시리즈를 반환합니다.

이 두 시리즈를 & 연산자로 결합하면, 두 조건을 모두 만족하는 행만 True가 됩니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 이커머스 회사에서 VIP 고객 관리 시스템을 개발한다고 가정해봅시다. "최근 3개월 동안 구매 횟수가 5회 이상이고, 총 구매금액이 50만원 이상인 고객"을 자동으로 VIP로 승급시키는 기능을 만들 때, 다중 조건 필터링을 활용하면 매우 효율적입니다.

실제로 많은 기업에서 고객 세그먼테이션에 이런 패턴을 적극적으로 사용하고 있습니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 각 조건을 괄호로 감싸지 않는 것입니다. df[df['지역'] == '서울' & df['구매금액'] >= 100000] 이렇게 작성하면 연산자 우선순위 때문에 예상과 다른 결과가 나오거나 오류가 발생합니다.

따라서 항상 각 조건을 명시적으로 괄호로 감싸야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

선배 박시니어 씨가 다가와 김개발 씨의 코드를 보더니 고개를 끄덕였습니다. "좋아요!

다중 조건 필터링을 제대로 사용했네요. 괄호도 빠뜨리지 않았고요." 다중 조건 필터링을 제대로 이해하면 복잡한 데이터에서 원하는 정보를 빠르게 추출할 수 있습니다.

여러분도 오늘 배운 내용을 실제 데이터 분석 프로젝트에 적용해 보세요.

실전 팁

💡 - &(AND), |(OR) 사용 시 각 조건을 반드시 괄호로 감싸세요

  • isin() 메서드를 활용하면 여러 값 중 하나와 일치하는지 확인할 수 있습니다
  • query() 메서드를 사용하면 SQL처럼 문자열로 조건을 표현할 수 있습니다

2. crosstab으로 교차표 생성

필터링된 데이터를 보고 있던 김개발 씨에게 팀장님이 또 다른 요청을 했습니다. "지역별로 회원등급이 어떻게 분포되어 있는지 표로 정리해줄 수 있어요?" 단순히 데이터를 보는 것만으로는 패턴을 파악하기 어려웠습니다.

crosstab은 두 개 이상의 범주형 변수 간의 빈도를 교차표 형태로 보여주는 함수입니다. 마치 엑셀의 피벗 테이블처럼 행과 열로 데이터를 재구성하여 한눈에 패턴을 파악할 수 있게 합니다.

주로 범주형 데이터 간의 관계를 탐색할 때 사용하며, 데이터의 분포를 시각적으로 이해하는 데 매우 유용합니다.

다음 코드를 살펴봅시다.

import pandas as pd

# 샘플 데이터 생성
df = pd.DataFrame({
    '지역': ['서울', '부산', '서울', '대구', '서울', '부산', '대구'],
    '회원등급': ['VIP', '일반', 'VIP', '일반', 'VVIP', 'VIP', '일반'],
    '성별': ['남', '여', '여', '남', '남', '여', '남']
})

# 지역과 회원등급의 교차표 생성
cross = pd.crosstab(df['지역'], df['회원등급'])
print(cross)

# 행과 열의 합계 추가
cross_with_margin = pd.crosstab(df['지역'], df['회원등급'], margins=True)
print(cross_with_margin)

김개발 씨는 필터링한 데이터를 엑셀로 복사해서 하나하나 세어보기 시작했습니다. 서울의 VIP가 몇 명, 부산의 일반 회원이 몇 명...

손이 많이 가는 작업이었습니다. 옆자리의 박시니어 씨가 이를 보더니 빙그레 웃으며 말했습니다.

"김 대리, 그렇게 하면 시간이 너무 오래 걸려요. crosstab 함수를 사용해보세요." 그렇다면 crosstab이란 정확히 무엇일까요?

쉽게 비유하자면, crosstab은 마치 학교 성적표의 석차 분포표와 같습니다. "1반에 A학점 몇 명, B학점 몇 명"처럼 두 가지 기준을 교차해서 빈도를 세는 것입니다.

이렇게 표로 정리하면 "아, 1반이 2반보다 A학점 학생이 많구나"라는 패턴을 즉시 파악할 수 있습니다. crosstab이 없던 시절에는 어땠을까요?

개발자들은 groupby로 그룹을 나누고, count로 개수를 세고, unstack으로 테이블 형태로 변환하는 복잡한 과정을 거쳐야 했습니다. 코드가 길어지고, 실수할 가능성도 높았습니다.

더 큰 문제는 코드를 작성하는 사람은 이해하지만, 다른 사람이 보면 의도를 파악하기 어렵다는 점이었습니다. 바로 이런 문제를 해결하기 위해 crosstab 함수가 등장했습니다.

crosstab을 사용하면 단 한 줄로 교차표를 만들 수 있습니다. 코드의 의도가 명확하게 드러나며, 추가 옵션으로 행과 열의 합계도 쉽게 표시할 수 있습니다.

무엇보다 데이터 분석가가 아닌 일반 직원도 결과를 쉽게 이해할 수 있다는 큰 장점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 pd.crosstab(df['지역'], df['회원등급'])은 지역을 행으로, 회원등급을 열로 하는 교차표를 생성합니다. 결과는 각 조합에 해당하는 데이터의 개수를 보여줍니다.

예를 들어 "서울 + VIP"에 해당하는 행이 몇 개인지 자동으로 계산됩니다. margins=True 옵션을 추가하면 각 행과 열의 합계가 'All'이라는 이름으로 추가됩니다.

이를 통해 전체 데이터의 분포를 더 쉽게 파악할 수 있습니다. 예를 들어 "서울 지역 전체 고객이 몇 명인지" 또는 "VIP 등급 고객이 전체 몇 명인지" 한눈에 볼 수 있습니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 온라인 교육 플랫폼을 운영한다고 가정해봅시다.

"연령대별로 어떤 강의 카테고리를 선호하는지" 분석할 때 crosstab을 사용하면 매우 효과적입니다. 20대는 프로그래밍 강의를, 30대는 재테크 강의를 많이 수강한다는 패턴을 발견하면, 타겟 마케팅 전략을 수립할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 연속형 데이터(나이, 금액 등)를 그대로 crosstab에 넣는 것입니다.

연속형 데이터는 값의 종류가 너무 많아서 교차표가 지나치게 커지고 해석이 어려워집니다. 따라서 먼저 구간으로 나누는 binning 작업을 한 후에 crosstab을 적용해야 합니다.

박시니어 씨의 설명을 들은 김개발 씨는 노트북을 열어 직접 코드를 작성했습니다. 단 두 줄만으로 깔끔한 교차표가 완성되었습니다.

"와, 정말 간단하네요!" crosstab을 제대로 이해하면 복잡한 데이터의 패턴을 빠르게 발견할 수 있습니다. 데이터 분석 보고서를 작성할 때 교차표는 필수 도구입니다.

실전 팁

💡 - normalize 옵션으로 빈도 대신 비율을 표시할 수 있습니다

  • 세 개 이상의 변수를 교차 분석할 때는 valuesaggfunc 옵션을 활용하세요
  • 연속형 데이터는 pd.cut 또는 pd.qcut으로 구간화한 후 사용하세요

3. pivot table 기본 사용법

교차표를 성공적으로 만든 김개발 씨에게 팀장님이 새로운 과제를 주었습니다. "지역별, 회원등급별 평균 구매금액을 정리해주세요." 이번에는 단순히 개수를 세는 것이 아니라 평균을 계산해야 했습니다.

pivot_table은 데이터를 재구조화하여 다양한 집계 함수를 적용할 수 있는 강력한 도구입니다. crosstab이 빈도만 세는 반면, pivot_table은 평균, 합계, 최댓값 등 다양한 통계를 계산할 수 있습니다.

엑셀의 피벗 테이블과 동일한 개념이며, 데이터 분석에서 가장 자주 사용되는 함수 중 하나입니다.

다음 코드를 살펴봅시다.

import pandas as pd
import numpy as np

# 샘플 데이터 생성
df = pd.DataFrame({
    '지역': ['서울', '부산', '서울', '대구', '서울', '부산'],
    '회원등급': ['VIP', '일반', 'VIP', '일반', 'VVIP', 'VIP'],
    '구매금액': [120000, 80000, 150000, 90000, 200000, 110000],
    '구매횟수': [3, 1, 5, 2, 7, 4]
})

# 지역과 회원등급별 평균 구매금액 피벗 테이블
pivot = df.pivot_table(
    values='구매금액',  # 집계할 값
    index='지역',        # 행으로 사용할 컬럼
    columns='회원등급',  # 열로 사용할 컬럼
    aggfunc='mean'      # 집계 함수 (평균)
)
print(pivot)

김개발 씨는 또다시 막막해졌습니다. crosstab은 개수만 세는 함수인데, 평균은 어떻게 계산하지?

엑셀이라면 피벗 테이블을 만들면 될 텐데... 바로 그때 박시니어 씨가 다시 나타났습니다.

"김 대리, Pandas에도 피벗 테이블이 있어요. pivot_table 함수를 사용하면 됩니다." 그렇다면 pivot_table이란 정확히 무엇일까요?

쉽게 비유하자면, pivot_table은 마치 식당의 매출 보고서와 같습니다. "지점별로 메뉴 카테고리별 평균 판매 금액"을 정리한다고 생각해보세요.

강남점의 한식 메뉴 평균 가격, 홍대점의 양식 메뉴 평균 가격처럼 여러 기준으로 데이터를 나누고, 각 그룹에 대해 원하는 계산을 수행합니다. 이렇게 정리하면 어느 지점의 어떤 메뉴가 수익성이 높은지 한눈에 파악할 수 있습니다.

pivot_table이 없던 시절에는 어땠을까요? 개발자들은 groupby로 여러 컬럼을 기준으로 그룹을 만들고, agg로 집계하고, unstack으로 테이블 형태로 변환하는 3단계 과정을 거쳐야 했습니다.

코드가 복잡해지고, 중간 결과를 저장할 변수도 필요했습니다. 더 큰 문제는 NaN(결측값) 처리와 같은 세부 사항을 일일이 신경 써야 한다는 점이었습니다.

바로 이런 문제를 해결하기 위해 pivot_table 함수가 등장했습니다. pivot_table을 사용하면 한 번의 함수 호출로 복잡한 집계 테이블을 만들 수 있습니다.

values로 집계할 값을, index로 행을, columns로 열을, aggfunc로 집계 함수를 지정하면 끝입니다. 게다가 NaN 처리, 행/열 합계 추가 등 다양한 옵션도 제공됩니다.

위의 코드를 한 줄씩 살펴보겠습니다. df.pivot_table() 함수는 네 가지 핵심 파라미터를 받습니다.

첫 번째, values='구매금액'은 "어떤 값을 집계할 것인가"를 지정합니다. 두 번째, index='지역'은 "행에 무엇을 배치할 것인가"를 결정합니다.

세 번째, columns='회원등급'은 "열에 무엇을 배치할 것인가"를 결정합니다. 마지막으로 aggfunc='mean'은 "어떤 방식으로 집계할 것인가"를 지정합니다.

'mean'은 평균을 의미하며, 'sum'(합계), 'count'(개수), 'max'(최댓값) 등 다양한 집계 함수를 사용할 수 있습니다. 결과는 지역별로 각 회원등급의 평균 구매금액을 보여주는 깔끔한 테이블이 됩니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 게임 회사에서 유저 행동 데이터를 분석한다고 가정해봅시다.

"레벨 구간별로 직업 클래스별 평균 플레이 시간"을 pivot_table로 만들면, 어떤 직업이 어느 레벨 구간에서 이탈률이 높은지 파악할 수 있습니다. 이를 바탕으로 게임 밸런스를 조정하거나 이벤트를 기획할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 values를 지정하지 않고 pivot_table을 사용하는 것입니다.

이 경우 모든 수치형 컬럼이 집계되어 의도하지 않은 결과가 나올 수 있습니다. 따라서 명시적으로 집계할 컬럼을 지정하는 것이 좋습니다.

또한 결측값이 있는 경우 fill_value 옵션으로 0이나 다른 값으로 채울 수 있습니다. 김개발 씨는 박시니어 씨가 알려준 대로 코드를 작성했습니다.

단 몇 줄만으로 엑셀 피벗 테이블과 똑같은 결과가 나왔습니다. "Python도 엑셀만큼 편하네요!" pivot_table을 제대로 이해하면 복잡한 데이터를 다양한 관점에서 분석할 수 있습니다.

엑셀에서 할 수 있는 거의 모든 집계 작업을 Python으로 자동화할 수 있습니다.

실전 팁

💡 - fill_value=0 옵션으로 NaN 대신 0으로 채울 수 있습니다

  • margins=True로 행과 열의 총합계를 추가할 수 있습니다
  • indexcolumns에 리스트를 전달하면 다중 인덱스를 사용할 수 있습니다

4. 여러 집계 함수 적용

피벗 테이블을 만든 김개발 씨에게 팀장님이 추가 요청을 했습니다. "평균만이 아니라 합계와 최댓값도 같이 보고 싶어요." 한 번에 여러 통계를 계산할 수는 없을까요?

aggfunc에 리스트나 딕셔너리를 전달하면 여러 집계 함수를 동시에 적용할 수 있습니다. 평균, 합계, 개수, 표준편차 등을 한 번에 계산하여 데이터를 다각도로 분석할 수 있습니다.

이를 통해 데이터의 전체적인 모습을 한눈에 파악할 수 있으며, 의사결정에 필요한 다양한 지표를 동시에 얻을 수 있습니다.

다음 코드를 살펴봅시다.

import pandas as pd
import numpy as np

# 샘플 데이터 생성
df = pd.DataFrame({
    '지역': ['서울', '부산', '서울', '대구', '서울', '부산', '대구'],
    '회원등급': ['VIP', '일반', 'VIP', '일반', 'VVIP', 'VIP', 'VIP'],
    '구매금액': [120000, 80000, 150000, 90000, 200000, 110000, 130000]
})

# 여러 집계 함수를 동시에 적용
pivot_multi = df.pivot_table(
    values='구매금액',
    index='지역',
    columns='회원등급',
    aggfunc=['mean', 'sum', 'count']  # 평균, 합계, 개수를 동시에 계산
)
print(pivot_multi)

# 서로 다른 컬럼에 다른 집계 함수 적용
pivot_dict = df.pivot_table(
    index='지역',
    values=['구매금액'],
    aggfunc={'구매금액': ['mean', 'max', 'min']}
)
print(pivot_dict)

김개발 씨는 고민에 빠졌습니다. 평균을 구하는 피벗 테이블과 합계를 구하는 피벗 테이블을 각각 만들어야 하나?

그럼 코드가 너무 길어질 텐데... 박시니어 씨가 김개발 씨의 화면을 보더니 말했습니다.

"한 번에 여러 통계를 계산할 수 있어요. aggfunc에 리스트를 전달하면 됩니다." 그렇다면 여러 집계 함수 적용이란 정확히 무엇일까요?

쉽게 비유하자면, 이것은 마치 학생 성적표에서 과목별로 평균, 최고점, 최저점을 동시에 표시하는 것과 같습니다. 수학 과목의 평균은 75점, 최고점은 95점, 최저점은 50점처럼 여러 지표를 함께 보면 학급의 전반적인 학업 수준을 더 정확히 파악할 수 있습니다.

데이터 분석도 마찬가지로, 하나의 통계만으로는 전체 그림을 보기 어렵습니다. 여러 집계 함수를 동시에 적용하는 기능이 없던 시절에는 어땠을까요?

개발자들은 각 집계 함수마다 별도의 pivot_table을 만들고, 나중에 concat이나 merge로 결과를 합치는 번거로운 작업을 해야 했습니다. 코드가 길어지고, 실수할 가능성도 높았습니다.

특히 인덱스가 일치하지 않으면 합치는 과정에서 데이터가 누락되거나 중복될 위험도 있었습니다. 바로 이런 문제를 해결하기 위해 aggfunc에 리스트를 전달하는 기능이 추가되었습니다.

aggfunc에 ['mean', 'sum', 'count']처럼 리스트를 전달하면, Pandas가 자동으로 각 집계 함수를 적용하고 결과를 다중 컬럼으로 정리해줍니다. 코드는 간결하지만, 결과는 매우 풍부합니다.

한 번의 함수 호출로 데이터를 여러 각도에서 분석할 수 있다는 큰 장점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

첫 번째 예제에서 aggfunc=['mean', 'sum', 'count']는 세 가지 집계 함수를 동시에 적용합니다. 결과는 다중 레벨 컬럼을 가진 DataFrame이 되며, 최상위 레벨은 집계 함수명(mean, sum, count), 하위 레벨은 회원등급이 됩니다.

이렇게 하면 "서울 지역 VIP 고객의 평균 구매금액은 얼마이고, 총 구매금액은 얼마인가"를 한눈에 볼 수 있습니다. 두 번째 예제는 더 세밀한 제어가 필요할 때 사용합니다.

aggfunc={'구매금액': ['mean', 'max', 'min']}처럼 딕셔너리를 전달하면, 특정 컬럼에 대해서만 원하는 집계 함수를 적용할 수 있습니다. 여러 컬럼이 있을 때 각각 다른 집계 함수를 적용하고 싶다면 이 방법이 유용합니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 물류 회사에서 배송 데이터를 분석한다고 가정해봅시다.

"지역별로 배송 소요 시간의 평균, 최댓값, 최솟값"을 동시에 확인하면, 어느 지역의 배송 품질이 일정한지, 어느 지역이 변동성이 큰지 파악할 수 있습니다. 평균은 좋지만 최댓값이 매우 크다면, 간혹 심각한 지연이 발생한다는 의미이므로 원인을 조사할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 너무 많은 집계 함수를 동시에 적용하는 것입니다.

10개, 20개의 통계를 한꺼번에 계산하면 결과 테이블이 너무 복잡해져서 오히려 해석이 어려워집니다. 따라서 분석 목적에 맞는 핵심 지표 3~5개만 선택하는 것이 좋습니다.

또한 다중 레벨 컬럼은 인덱싱이 복잡하므로, 필요하다면 droplevel이나 reset_index로 구조를 단순화하세요. 김개발 씨는 리스트를 사용해서 코드를 수정했습니다.

단 한 번의 함수 호출로 평균, 합계, 개수가 모두 계산되었습니다. "이렇게 간단할 줄이야!" 여러 집계 함수를 동시에 적용하면 데이터를 다각도로 분석할 수 있습니다.

평균만 보는 것보다 훨씬 풍부한 인사이트를 얻을 수 있습니다.

실전 팁

💡 - np.mean, np.std 등 NumPy 함수도 aggfunc에 사용할 수 있습니다

  • 커스텀 함수를 정의하여 aggfunc에 전달할 수도 있습니다
  • 결과의 컬럼명이 복잡하다면 rename이나 set_axis로 정리하세요

5. 피벗 결과 시각화

완성된 피벗 테이블을 팀장님께 보고했더니, "표만 보면 한눈에 안 들어오네요. 그래프로 만들어줄 수 있나요?"라는 요청을 받았습니다.

숫자 테이블을 어떻게 시각화하면 좋을까요?

피벗 테이블의 plot() 메서드를 사용하면 집계 결과를 바로 그래프로 표현할 수 있습니다. 막대 그래프, 선 그래프, 히트맵 등 다양한 시각화 방식을 선택할 수 있으며, 데이터의 패턴과 트렌드를 직관적으로 파악할 수 있습니다.

숫자로만 보던 데이터가 시각화되면 비전문가도 쉽게 이해할 수 있어 보고서나 발표 자료에 매우 유용합니다.

다음 코드를 살펴봅시다.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 한글 폰트 설정 (한글 깨짐 방지)
plt.rcParams['font.family'] = 'Malgun Gothic'
plt.rcParams['axes.unicode_minus'] = False

# 샘플 데이터 생성
df = pd.DataFrame({
    '지역': ['서울', '부산', '서울', '대구', '서울', '부산', '대구', '부산'],
    '회원등급': ['VIP', '일반', 'VIP', '일반', 'VVIP', 'VIP', 'VIP', '일반'],
    '구매금액': [120000, 80000, 150000, 90000, 200000, 110000, 130000, 85000]
})

# 피벗 테이블 생성
pivot = df.pivot_table(values='구매금액', index='지역', columns='회원등급', aggfunc='mean')

# 막대 그래프로 시각화
pivot.plot(kind='bar', figsize=(10, 6), title='지역별 회원등급별 평균 구매금액')
plt.ylabel('평균 구매금액')
plt.show()

# 히트맵으로 시각화
plt.figure(figsize=(8, 6))
sns.heatmap(pivot, annot=True, fmt='.0f', cmap='YlOrRd')
plt.title('지역별 회원등급별 평균 구매금액 히트맵')
plt.show()

김개발 씨는 막막했습니다. 그래프를 만들려면 또 새로운 라이브러리를 배워야 하나?

데이터를 어떻게 변환해야 그래프 그리기에 적합한 형태가 될까? 박시니어 씨가 김개발 씨의 고민을 알아차리고 말했습니다.

"걱정하지 마세요. 피벗 테이블은 바로 plot() 메서드를 호출할 수 있어요.

별도의 데이터 변환이 필요 없습니다." 그렇다면 피벗 결과 시각화란 정확히 무엇일까요? 쉽게 비유하자면, 이것은 마치 가계부를 그래프로 만드는 것과 같습니다.

월별 지출 내역을 숫자로만 보면 어느 달에 지출이 많았는지 파악하기 어렵지만, 막대 그래프로 그리면 한눈에 "아, 7월에 지출이 급증했구나"를 알 수 있습니다. 데이터 분석도 마찬가지로, 시각화를 통해 숨겨진 패턴을 발견할 수 있습니다.

시각화 기능이 통합되지 않았던 시절에는 어땠을까요? 개발자들은 피벗 테이블을 만든 후, 데이터를 다시 리스트나 배열로 변환하고, matplotlib이나 seaborn의 복잡한 문법을 사용해서 일일이 그래프를 그려야 했습니다.

x축, y축 설정, 범례 추가, 색상 지정 등 신경 써야 할 것이 너무 많았습니다. 실수하면 그래프가 이상하게 그려지거나 아예 오류가 발생하기도 했습니다.

바로 이런 문제를 해결하기 위해 DataFrame의 plot() 메서드가 등장했습니다. Pandas는 matplotlib을 내부적으로 통합하여, DataFrame이나 피벗 테이블에서 바로 plot() 메서드를 호출할 수 있게 했습니다.

kind='bar'로 막대 그래프, kind='line'으로 선 그래프를 그릴 수 있으며, 기본적인 설정은 자동으로 처리됩니다. 게다가 seaborn의 heatmap을 사용하면 피벗 테이블을 색상으로 표현하여 값의 크기를 직관적으로 비교할 수 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 한글 폰트 설정이 중요합니다.

plt.rcParams['font.family'] = 'Malgun Gothic'은 한글이 깨지지 않도록 폰트를 지정합니다. 다음으로 pivot.plot(kind='bar')는 피벗 테이블을 막대 그래프로 그립니다.

figsize는 그래프 크기를, title은 제목을 설정합니다. sns.heatmap(pivot, annot=True, fmt='.0f', cmap='YlOrRd')는 히트맵을 그립니다.

annot=True는 각 셀에 값을 표시하고, fmt='.0f'는 소수점 없이 정수로 표시하라는 의미입니다. cmap='YlOrRd'는 노란색-주황색-빨간색 그라데이션 색상을 사용합니다.

값이 클수록 진한 빨간색으로 표시되어 한눈에 높은 값을 찾을 수 있습니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 온라인 광고 대행사에서 캠페인 성과를 분석한다고 가정해봅시다. "매체별, 시간대별 클릭률"을 피벗 테이블로 만들고 히트맵으로 시각화하면, 어느 매체의 어느 시간대에 광고를 집행해야 효율이 좋은지 즉시 파악할 수 있습니다.

이를 클라이언트 보고서에 첨부하면 전문적이고 설득력 있는 자료가 됩니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 시각화 방법을 잘못 선택하는 것입니다. 예를 들어 범주가 너무 많으면 막대 그래프가 복잡해지고, 시계열 데이터가 아닌데 선 그래프를 그리면 오해를 불러일으킬 수 있습니다.

따라서 데이터의 특성에 맞는 적절한 그래프를 선택해야 합니다. 일반적으로 비교는 막대 그래프, 트렌드는 선 그래프, 전체 분포는 히트맵이 적합합니다.

김개발 씨는 코드를 실행하고 그래프를 확인했습니다. 숫자로만 보던 데이터가 색색의 막대와 히트맵으로 표현되니 훨씬 이해하기 쉬웠습니다.

"이제 보고서 완성이네요!" 피벗 결과를 시각화하면 데이터의 패턴을 즉시 파악할 수 있습니다. 보고서나 발표 자료에 그래프를 포함하면 전달력이 크게 향상됩니다.

실전 팁

💡 - kind 파라미터로 'bar', 'barh', 'line', 'area' 등 다양한 그래프를 선택할 수 있습니다

  • stacked=True 옵션으로 누적 막대 그래프를 만들 수 있습니다
  • cmap 파라미터로 히트맵 색상을 변경할 수 있습니다 ('viridis', 'coolwarm' 등)

6. melt로 데이터 변환

피벗 테이블로 분석을 마친 김개발 씨에게 또 다른 과제가 주어졌습니다. "이 데이터를 머신러닝 모델에 넣으려면 형태를 바꿔야 하는데..." 넓은 형태의 피벗 테이블을 다시 긴 형태로 되돌릴 수는 없을까요?

melt는 피벗의 반대 작업으로, 넓은 형태(wide format)의 데이터를 긴 형태(long format)로 변환합니다. 여러 컬럼에 흩어진 값들을 하나의 컬럼으로 모아서 행으로 만들어줍니다.

머신러닝이나 특정 시각화 라이브러리는 긴 형태의 데이터를 요구하므로, melt는 데이터 전처리에서 자주 사용되는 필수 도구입니다.

다음 코드를 살펴봅시다.

import pandas as pd

# 넓은 형태의 샘플 데이터 생성 (피벗 테이블 결과와 유사)
df_wide = pd.DataFrame({
    '지역': ['서울', '부산', '대구'],
    'VIP': [135000, 110000, 130000],
    '일반': [85000, 82500, 90000],
    'VVIP': [200000, None, None]
})

print("넓은 형태 (Wide Format):")
print(df_wide)

# melt를 사용하여 긴 형태로 변환
df_long = df_wide.melt(
    id_vars='지역',           # 고정할 컬럼 (식별자 역할)
    var_name='회원등급',       # 컬럼명이 들어갈 새 컬럼 이름
    value_name='평균구매금액'  # 값이 들어갈 새 컬럼 이름
)

print("\n긴 형태 (Long Format):")
print(df_long)

김개발 씨는 또 다른 문제에 직면했습니다. 피벗 테이블로 만든 데이터는 가로로 펼쳐져 있는데, 머신러닝 라이브러리에서는 세로로 긴 데이터를 요구한다는 것입니다.

박시니어 씨가 다가와 설명했습니다. "데이터 형태를 바꿔야 할 때가 많아요.

피벗의 반대 작업인 melt를 사용하면 됩니다." 그렇다면 melt란 정확히 무엇일까요? 쉽게 비유하자면, melt는 마치 스프레드시트를 데이터베이스 테이블로 바꾸는 것과 같습니다.

엑셀에서 "1월, 2월, 3월"이 각각 컬럼으로 있는 매출 데이터를, "월"과 "매출액"이라는 두 개의 컬럼으로 정리하는 작업입니다. 가로로 펼쳐진 데이터를 세로로 쌓아 올리는 것이죠.

이렇게 하면 데이터가 길어지지만, 각 행이 하나의 관측값을 나타내므로 분석하기 더 편리합니다. melt가 없던 시절에는 어땠을까요?

개발자들은 반복문을 돌면서 각 컬럼의 값을 하나씩 꺼내서 새로운 DataFrame에 추가하는 복잡한 코드를 작성해야 했습니다. 코드가 길고 느리며, 실수하기도 쉬웠습니다.

특히 컬럼이 수십 개, 수백 개로 많아지면 성능 문제도 발생했습니다. 바로 이런 문제를 해결하기 위해 melt 함수가 등장했습니다.

melt를 사용하면 단 한 줄로 데이터 형태를 변환할 수 있습니다. id_vars로 고정할 컬럼을 지정하고, var_name으로 컬럼명이 들어갈 새 컬럼의 이름을, value_name으로 값이 들어갈 새 컬럼의 이름을 지정하면 끝입니다.

내부적으로 최적화되어 있어 성능도 매우 빠릅니다. 위의 코드를 한 줄씩 살펴보겠습니다.

원본 데이터 df_wide는 지역 컬럼과 VIP, 일반, VVIP 컬럼으로 구성되어 있습니다. 이것은 전형적인 넓은 형태입니다.

df_wide.melt(id_vars='지역')을 실행하면, '지역' 컬럼은 그대로 유지되고, 나머지 컬럼들(VIP, 일반, VVIP)이 '회원등급'이라는 하나의 컬럼으로 합쳐집니다. 결과를 보면 원래 3행 4열이었던 데이터가 9행 3열로 변환됩니다.

각 회원등급이 별도의 행으로 분리되어, "서울-VIP", "서울-일반", "서울-VVIP"처럼 모든 조합이 개별 행이 됩니다. 이렇게 변환된 데이터는 대부분의 통계 모델이나 시각화 라이브러리에서 선호하는 형태입니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 날씨 데이터를 분석한다고 가정해봅시다.

원본 데이터가 "도시, 1월기온, 2월기온, 3월기온..." 형태로 되어 있다면, 시계열 분석이나 머신러닝 모델에 바로 사용하기 어렵습니다. melt로 "도시, 월, 기온" 형태로 변환하면, 시계열 라이브러리나 모델에 쉽게 적용할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 id_vars를 빠뜨리는 것입니다.

id_vars를 지정하지 않으면 모든 컬럼이 melt되어 의도하지 않은 결과가 나올 수 있습니다. 또한 원본 데이터에 결측값(NaN)이 있으면 melt 결과에도 그대로 남으므로, 필요하다면 **dropna()**로 제거해야 합니다.

김개발 씨는 melt를 사용해서 데이터를 변환했습니다. 가로로 펼쳐졌던 데이터가 세로로 깔끔하게 정리되었습니다.

"이제 머신러닝 모델에 넣을 수 있겠네요!" melt를 제대로 이해하면 데이터 형태를 자유자재로 변환할 수 있습니다. 피벗과 melt는 데이터 분석에서 가장 자주 사용되는 변환 도구입니다.

실전 팁

💡 - value_vars로 변환할 컬럼을 명시적으로 지정할 수 있습니다

  • melt 후 NaN이 생기면 **dropna()**로 제거하세요
  • pivot_tablemelt는 서로 반대 작업이므로, 필요에 따라 형태를 변환할 수 있습니다

7. 분석 인사이트 도출

모든 데이터 변환과 시각화를 마친 김개발 씨에게 팀장님이 마지막 질문을 했습니다. "그래서 결론이 뭔가요?

우리가 어떤 액션을 취해야 할까요?" 기술적인 작업은 끝났지만, 비즈니스 인사이트를 도출하는 것이 진짜 목표였습니다.

분석 인사이트 도출은 기술적인 분석 결과를 비즈니스 가치로 전환하는 과정입니다. 단순히 "평균이 얼마다"를 넘어서, "왜 그런 결과가 나왔는지", "어떤 의사결정을 내려야 하는지"를 해석하는 것입니다.

데이터 분석의 궁극적인 목적은 인사이트를 발견하고 액션을 제안하는 것이며, 이것이 데이터 과학자와 단순 데이터 처리자의 차이를 만듭니다.

다음 코드를 살펴봅시다.

import pandas as pd
import numpy as np

# 종합 분석 예제
df = pd.DataFrame({
    '지역': ['서울', '부산', '서울', '대구', '서울', '부산', '대구', '부산'] * 3,
    '회원등급': ['VIP', '일반', 'VIP', '일반', 'VVIP', 'VIP', 'VIP', '일반'] * 3,
    '구매금액': [120000, 80000, 150000, 90000, 200000, 110000, 130000, 85000] * 3,
    '구매횟수': [3, 1, 5, 2, 7, 4, 4, 1] * 3
})

# 1. 지역별 회원등급별 평균 분석
pivot_avg = df.pivot_table(values='구매금액', index='지역', columns='회원등급', aggfunc='mean')

# 2. 구매 빈도와 금액의 상관관계
correlation = df[['구매금액', '구매횟수']].corr()

# 3. 지역별 총 매출과 고객 수
summary = df.groupby('지역').agg({
    '구매금액': ['sum', 'mean'],
    '회원등급': 'count'  # 고객 수
}).round(0)

print("지역별 회원등급별 평균 구매금액:")
print(pivot_avg)
print("\n구매금액과 구매횟수 상관계수:")
print(correlation)
print("\n지역별 총 매출 및 고객 수:")
print(summary)

# 인사이트: 서울 VVIP 고객의 평균 구매금액이 가장 높음
# 액션: 서울 지역 VVIP 고객 대상 프리미엄 서비스 강화

김개발 씨는 완벽한 피벗 테이블과 그래프를 만들었습니다. 하지만 팀장님의 질문에 대답하지 못했습니다.

숫자와 그래프는 있지만, 그것이 무엇을 의미하는지, 무엇을 해야 하는지 명확하지 않았기 때문입니다. 박시니어 씨가 김개발 씨의 화면을 보며 조언했습니다.

"데이터 분석의 진짜 가치는 인사이트에 있어요. 숫자가 아니라 그 숫자가 말하는 이야기를 찾아야 합니다." 그렇다면 분석 인사이트 도출이란 정확히 무엇일까요?

쉽게 비유하자면, 인사이트 도출은 마치 의사가 검사 결과를 보고 진단하는 것과 같습니다. 혈압이 140이라는 숫자 자체는 그냥 데이터일 뿐입니다.

하지만 의사는 "고혈압이므로 운동과 식이요법이 필요합니다"라는 인사이트를 제공합니다. 데이터 분석도 마찬가지로, 평균 구매금액이 12만원이라는 사실보다 "VIP 고객의 구매력이 높으므로 프리미엄 상품을 강화해야 한다"는 결론이 중요합니다.

인사이트 도출 없이 데이터만 제시하던 시절에는 어땠을까요? 개발자들은 완벽한 표와 그래프를 만들어도 "그래서 뭘 하라는 거죠?"라는 질문을 받았습니다.

의사결정권자는 통계 전문가가 아니므로, 숫자만 보고는 판단하기 어려웠습니다. 결국 분석 결과가 실제 비즈니스로 이어지지 못하고, 데이터 분석팀의 가치도 제대로 인정받지 못했습니다.

바로 이런 문제를 해결하기 위해 데이터 과학에서 인사이트 도출스토리텔링이 강조되기 시작했습니다. 단순히 통계를 계산하는 것을 넘어, 데이터가 말하는 이야기를 찾고, 비즈니스 맥락에서 해석하고, 구체적인 액션을 제안하는 것이 데이터 분석가의 핵심 역량이 되었습니다.

"평균이 얼마다"가 아니라 "왜 이런 결과가 나왔고, 무엇을 해야 하는가"를 답해야 합니다. 위의 코드를 통해 인사이트 도출 과정을 살펴보겠습니다.

먼저 지역별 회원등급별 평균 구매금액을 피벗 테이블로 정리합니다. 여기서 "서울 VVIP 고객의 평균 구매금액이 20만원으로 가장 높다"는 사실을 발견합니다.

다음으로 구매금액과 구매횟수의 상관계수를 계산합니다. 상관계수가 높다면 "자주 구매하는 고객이 더 많은 금액을 지출한다"는 패턴을 확인할 수 있습니다.

마지막으로 지역별 총 매출과 고객 수를 집계합니다. 만약 서울의 고객 수는 적지만 총 매출이 높다면, "서울은 고가치 고객이 집중된 지역"이라는 인사이트를 얻을 수 있습니다.

이 세 가지 분석을 종합하면, "서울 지역 VVIP 고객에게 프리미엄 서비스와 고가 상품을 집중적으로 제공해야 한다"는 액션을 도출할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 구독 서비스 회사에서 이탈률을 분석한다고 가정해봅시다. 데이터를 분석한 결과 "가입 후 7일 이내에 특정 기능을 사용하지 않은 고객의 이탈률이 80%"라는 사실을 발견했습니다.

여기서 인사이트는 "초기 온보딩이 매우 중요하다"이고, 액션은 "가입 후 3일 이내에 해당 기능 사용을 유도하는 푸시 알림과 튜토리얼을 강화한다"가 됩니다. 하지만 주의할 점도 있습니다.

초보 분석가들이 흔히 하는 실수 중 하나는 상관관계를 인과관계로 착각하는 것입니다. "VIP 고객이 구매금액이 높다"는 것은 VIP 등급이 구매금액을 높인 것이 아니라, 구매금액이 높은 고객을 VIP로 분류한 것일 수 있습니다.

따라서 인사이트를 도출할 때는 항상 인과관계를 신중히 검토해야 합니다. 또한 확증편향을 조심해야 합니다.

원하는 결과를 증명하기 위해 데이터를 왜곡하면 안 됩니다. 김개발 씨는 박시니어 씨의 조언을 따라 분석 결과를 정리했습니다.

"서울 VVIP 고객의 평균 구매금액이 20만원으로 가장 높습니다. 이들은 전체 고객의 5%에 불과하지만 매출의 30%를 차지합니다.

따라서 서울 지역 VVIP 고객을 위한 프리미엄 라인을 강화하고, 전용 고객센터를 운영하는 것을 제안합니다." 팀장님은 고개를 끄덕였습니다. "이제 뭘 해야 할지 명확하네요.

바로 실행에 옮기겠습니다." 김개발 씨는 데이터 분석의 진짜 가치를 깨달았습니다. 인사이트 도출은 데이터 분석의 최종 목표입니다.

기술적인 분석 능력과 비즈니스 이해를 결합해야 진정한 가치를 만들 수 있습니다.

실전 팁

💡 - 항상 "So What?(그래서 뭐?)"을 질문하며 인사이트를 깊이 있게 파고드세요

  • 상관관계와 인과관계를 명확히 구분하세요
  • 인사이트를 발표할 때는 데이터 → 인사이트 → 액션의 순서로 구조화하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#Pandas#DataAnalysis#Pivot#Crosstab

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.