포스트

[Python 100일 챌린지] Day 68 - 데이터 시각화 실전

[Python 100일 챌린지] Day 68 - 데이터 시각화 실전

다양한 차트로 데이터를 표현해봅시다! 🎨

원 그래프, 히스토그램, 산점도… 목적에 맞는 차트 선택이 중요해요! 실무에서 자주 쓰는 시각화를 배워봅시다! 📊

(35-45분 완독 ⭐⭐)

💡 Day 67 복습: 어제 배운 것

함수 용도 예시
plt.plot() 선 그래프 시간에 따른 변화
plt.bar() 막대 그래프 항목 간 비교

오늘은 여기에 원 그래프, 히스토그램, 산점도를 추가로 배워요!

🎯 오늘의 학습 목표

📚 사전 지식


🎯 학습 목표 1: 원 그래프와 도넛 차트

💡 원 그래프는 언제 쓸까요?

“전체 중에서 각 항목이 차지하는 비율”을 보여줄 때 사용해요!

좋은 예 안 좋은 예
시장 점유율 (합이 100%) 연도별 매출 변화 (선 그래프가 적합)
예산 배분 비율 점수 비교 (막대 그래프가 적합)

⚠️ 주의: 원 그래프는 항목이 5개 이하일 때 가장 보기 좋아요! 너무 많으면 “기타”로 묶으세요.

1.1 기본 원 그래프

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt

# 한글 폰트 설정
plt.rcParams['font.family'] = 'AppleGothic'
plt.rcParams['axes.unicode_minus'] = False

labels = ['Python', 'Java', 'JavaScript', 'C++', '기타']
sizes = [35, 25, 20, 10, 10]

plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.title('프로그래밍 언어 점유율')
plt.show()

💡 autopct 이해하기: '%1.1f%%'소수점 1자리까지 퍼센트 표시라는 뜻이에요. %1.1f는 소수점 1자리, %%는 % 기호를 의미해요!

1.2 원 그래프 꾸미기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import matplotlib.pyplot as plt

plt.rcParams['font.family'] = 'AppleGothic'

labels = ['Python', 'Java', 'JavaScript', 'C++', '기타']
sizes = [35, 25, 20, 10, 10]
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
explode = (0.1, 0, 0, 0, 0)  # Python만 튀어나오게

plt.pie(sizes,
        labels=labels,
        colors=colors,
        explode=explode,
        autopct='%1.1f%%',  # 퍼센트 표시
        shadow=True,        # 그림자
        startangle=90)      # 시작 각도

plt.title('프로그래밍 언어 점유율')
plt.show()

1.3 도넛 차트

💡 원 그래프 vs 도넛 차트

구분 원 그래프 도넛 차트
모양 꽉 찬 원 가운데가 빈 원
장점 단순하고 직관적 가운데에 정보 추가 가능
사용 예 단순 비율 표시 총합, 제목 등 강조할 때

도넛 차트는 가운데에 “총 매출: 1억” 같은 정보를 넣을 수 있어요!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import matplotlib.pyplot as plt

plt.rcParams['font.family'] = 'AppleGothic'

labels = ['Python', 'Java', 'JavaScript', '기타']
sizes = [40, 30, 20, 10]
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']

# 도넛 차트 = 원 그래프 + 가운데 원
fig, ax = plt.subplots()
ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%')

# 가운데 흰 원 추가 (반지름 0.5인 원)
centre_circle = plt.Circle((0, 0), 0.5, fc='white')
ax.add_patch(centre_circle)

# 가운데 텍스트
ax.text(0, 0, '언어\n점유율', ha='center', va='center', fontsize=12)

plt.title('프로그래밍 언어 점유율')
plt.show()

🎯 학습 목표 2: 히스토그램과 산점도

💡 히스토그램 vs 산점도, 언제 쓸까?

차트 목적 질문 예시
히스토그램 하나의 데이터 분포 확인 “학생들 점수가 어떻게 분포되어 있지?”
산점도 두 데이터 간 관계 확인 “공부 시간과 점수가 관련 있을까?”

비유로 이해하기:

  • 히스토그램 = 반 학생들의 키를 그룹별로 세기 (150~155cm: 5명, 155~160cm: 8명…)
  • 산점도 = 학생마다 키와 몸무게를 점으로 찍기 (관계가 보임)

2.1 히스토그램 (분포 확인)

데이터가 어떻게 분포되어 있는지 한눈에 볼 수 있어요!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.family'] = 'AppleGothic'

# 정규분포 데이터 생성
np.random.seed(42)  # 동일한 결과 재현을 위한 시드 설정
scores = np.random.normal(70, 15, 100)  # 평균 70, 표준편차 15, 100개 데이터

# bins=10: 데이터를 10개 구간으로 나눔
# alpha=0.7: 투명도 (0~1, 1이면 불투명)
plt.hist(scores, bins=10, edgecolor='black', alpha=0.7)
plt.title('학생 점수 분포')
plt.xlabel('점수')
plt.ylabel('학생 수')
plt.show()

💡 bins 이해하기

bins=10은 데이터 범위를 10개 구간(막대)으로 나눈다는 뜻이에요.

bins 값 결과 적합한 상황
작음 (5) 막대가 두꺼움, 대략적 분포 데이터가 적을 때
큼 (30) 막대가 얇음, 세밀한 분포 데이터가 많을 때
자동 bins='auto'로 최적값 계산 잘 모르겠을 때

2.2 히스토그램 비교

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.family'] = 'AppleGothic'

np.random.seed(42)
class_a = np.random.normal(75, 10, 50)
class_b = np.random.normal(70, 15, 50)

plt.hist(class_a, bins=10, alpha=0.5, label='A반')
plt.hist(class_b, bins=10, alpha=0.5, label='B반')

plt.title('반별 점수 분포')
plt.xlabel('점수')
plt.ylabel('학생 수')
plt.legend()
plt.show()

2.3 산점도 (상관관계)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.family'] = 'AppleGothic'

np.random.seed(42)
study_hours = np.random.uniform(1, 10, 50)
scores = study_hours * 8 + np.random.normal(0, 5, 50) + 20

plt.scatter(study_hours, scores, alpha=0.7)
plt.title('공부 시간 vs 점수')
plt.xlabel('공부 시간')
plt.ylabel('점수')

# 추세선 추가 (1차 함수로 데이터 경향 표현)
z = np.polyfit(study_hours, scores, 1)  # 1차 다항식 계수 계산
p = np.poly1d(z)  # 계수로 함수 생성
plt.plot(study_hours, p(study_hours), "r--", alpha=0.8, label='추세선')

plt.legend()
plt.show()

💡 추세선(Trend Line)이란?

데이터의 전체적인 경향을 보여주는 선이에요.

1
2
3
4
5
산점도만 있을 때:        추세선 추가 후:
  ·  ·                    ·  · ↗
 ·    ·                  ·  ↗ ·
  · ·                     ↗· ·
                         "아! 우상향하는구나!"
  • np.polyfit(x, y, 1): 데이터에 가장 잘 맞는 1차 함수(직선) 계수 계산
  • np.poly1d(z): 그 계수로 함수 생성

2.4 버블 차트

💡 버블 차트는 산점도의 확장!

산점도는 2가지 정보(x, y)를 보여주지만, 버블 차트는 3가지 정보를 보여줘요:

  • x축: 첫 번째 변수
  • y축: 두 번째 변수
  • 버블 크기: 세 번째 변수 (예: 매출액, 인구수)

예: 국가별 GDP(x) vs 기대수명(y), 버블 크기 = 인구수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.family'] = 'AppleGothic'

# 데이터
x = [1, 2, 3, 4, 5]
y = [10, 20, 15, 25, 30]
sizes = [100, 200, 150, 300, 250]  # 버블 크기 (세 번째 정보!)

plt.scatter(x, y, s=sizes, alpha=0.5, c=['red', 'blue', 'green', 'orange', 'purple'])
plt.title('버블 차트')
plt.xlabel('X축')
plt.ylabel('Y축')
plt.show()

🎯 학습 목표 3: Pandas와 함께 시각화

💡 왜 Pandas로 그래프를 그릴까요?

방식 코드량 특징
Matplotlib만 많음 세밀한 조정 가능
Pandas + Matplotlib 적음 DataFrame에서 바로 그래프!

Pandas의 df.plot()은 내부적으로 Matplotlib을 호출하지만, 코드가 훨씬 간단해요!

3.1 DataFrame에서 바로 그래프

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.family'] = 'AppleGothic'

df = pd.DataFrame({
    '': ['1월', '2월', '3월', '4월', '5월'],
    '매출': [100, 120, 115, 130, 145],
    '비용': [80, 85, 90, 95, 100]
})

# Pandas로 바로 그리기!
df.plot(x='', y=['매출', '비용'], kind='line')
plt.title('월별 매출/비용')
plt.ylabel('금액(만원)')
plt.show()

💡 Pandas plot의 kind 옵션 정리

kind 차트 종류 용도
'line' 선 그래프 시간에 따른 변화 (기본값)
'bar' 세로 막대 항목 비교
'barh' 가로 막대 항목이 많을 때 비교
'pie' 원 그래프 비율 표현
'hist' 히스토그램 분포 확인
'scatter' 산점도 두 변수 관계
'box' 박스플롯 분포 + 이상치 확인
'area' 영역 그래프 누적 데이터 표현

3.2 다양한 Pandas 차트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.family'] = 'AppleGothic'

df = pd.DataFrame({
    '제품': ['A', 'B', 'C', 'D'],
    '판매량': [300, 250, 180, 200]
})

# 막대 그래프
df.plot(x='제품', y='판매량', kind='bar', color='skyblue')
plt.title('제품별 판매량')
plt.ylabel('판매량')
plt.show()

# 원 그래프
df.plot(y='판매량', kind='pie', labels=df['제품'], autopct='%1.1f%%')
plt.title('제품별 판매 비율')
plt.ylabel('')
plt.show()

3.3 그룹 데이터 시각화

💡 피벗 테이블 → 시각화가 자연스러운 이유

Day 66에서 배운 피벗 테이블 기억나시나요?

1
2
3
4
5
원래 데이터:              피벗 후:
부서   분기   매출         부서    영업  개발
영업  1분기  100    →     1분기   100   80
개발  1분기   80          2분기   120   90
...                       (이 형태가 그래프에 딱!)

피벗 테이블은 행=x축, 열=범례 형태라서 바로 plot()하면 깔끔한 차트가 나와요!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.family'] = 'AppleGothic'

df = pd.DataFrame({
    '부서': ['영업', '영업', '개발', '개발', '마케팅', '마케팅'],
    '분기': ['1분기', '2분기', '1분기', '2분기', '1분기', '2분기'],
    '매출': [100, 120, 80, 90, 60, 75]
})

# 피벗 후 시각화
pivot = df.pivot(index='분기', columns='부서', values='매출')
print(pivot)  # 피벗 결과 확인
pivot.plot(kind='bar')
plt.title('부서별 분기 매출')
plt.ylabel('매출(만원)')
plt.legend(title='부서')
plt.show()

🎯 학습 목표 4: 차트 선택 가이드

4.1 목적별 차트 선택

graph TD
    A[데이터 유형?] --> B{수치 비교}
    A --> C{추세 분석}
    A --> D{분포 확인}
    A --> E{비율 표현}
    A --> F{관계 분석}

    B --> B1[막대 그래프]
    C --> C1[선 그래프]
    D --> D1[히스토그램]
    E --> E1[원/도넛 차트]
    F --> F1[산점도]

4.2 차트별 사용 예시

차트 용도 예시
선 그래프 시간에 따른 변화 주가, 기온 변화
막대 그래프 항목 간 비교 매출 비교, 인기도
원 그래프 전체 대비 비율 시장 점유율
히스토그램 데이터 분포 점수 분포, 나이 분포
산점도 두 변수 관계 키-몸무게, 공부-성적

4.3 실전 대시보드 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

plt.rcParams['font.family'] = 'AppleGothic'

# 샘플 데이터
np.random.seed(42)
months = ['1월', '2월', '3월', '4월', '5월', '6월']
sales = [120, 135, 128, 145, 160, 175]
costs = [100, 105, 110, 115, 120, 125]
categories = ['전자', '의류', '식품', '기타']
cat_values = [40, 30, 20, 10]
daily_sales = np.random.normal(50, 10, 30)

# 2x2 대시보드
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 1. 매출 추이 (선 그래프)
axes[0, 0].plot(months, sales, 'b-o', label='매출')
axes[0, 0].plot(months, costs, 'r--s', label='비용')
axes[0, 0].set_title('월별 매출/비용 추이')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# 2. 카테고리 비율 (원 그래프)
axes[0, 1].pie(cat_values, labels=categories, autopct='%1.1f%%',
               colors=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'])
axes[0, 1].set_title('카테고리별 판매 비율')

# 3. 일일 매출 분포 (히스토그램)
axes[1, 0].hist(daily_sales, bins=10, edgecolor='black', alpha=0.7)
axes[1, 0].set_title('일일 매출 분포')
axes[1, 0].set_xlabel('매출(만원)')
axes[1, 0].set_ylabel('일수')

# 4. 월별 매출 비교 (막대 그래프)
colors = ['#3498db', '#3498db', '#3498db', '#3498db', '#2ecc71', '#2ecc71']
axes[1, 1].bar(months, sales, color=colors)
axes[1, 1].set_title('월별 매출 현황')
axes[1, 1].set_ylabel('매출(만원)')

plt.tight_layout()
plt.savefig('dashboard.png', dpi=150)
plt.show()

💡 실전 팁

✅ 시각화 모범 사례

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import matplotlib.pyplot as plt

# 1. 명확한 제목과 레이블
plt.title('명확한 제목')
plt.xlabel('X축이 무엇인지')
plt.ylabel('Y축이 무엇인지')

# 2. 적절한 색상 선택
# - 대비가 명확한 색상 사용
# - 색맹 친화적 팔레트 고려

# 3. 불필요한 요소 제거
# - 3D 효과 지양
# - 과도한 장식 제거

# 4. 데이터 강조
# - 중요 데이터 하이라이트
# - 적절한 범례 배치

🧪 연습 문제

문제: 종합 시각화 만들기

다음 데이터로 4개 차트가 포함된 대시보드를 만드세요.

1
2
3
4
5
data = {
    '제품': ['노트북', '스마트폰', '태블릿', '이어폰'],
    '1분기': [100, 150, 80, 200],
    '2분기': [120, 160, 90, 220]
}
💡 힌트 보기

단계별 접근법:

  1. 한글 폰트 설정부터 시작!
    1
    
    plt.rcParams['font.family'] = 'AppleGothic'
    
  2. 2x2 대시보드 틀 만들기
    1
    
    fig, axes = plt.subplots(2, 2, figsize=(12, 10))
    
  3. 4개 차트 아이디어:
    • axes[0, 0]: 분기별 비교 → 그룹 막대 그래프 (Day 67에서 배움)
    • axes[0, 1]: 1분기 비율 → 원 그래프 (pie)
    • axes[1, 0]: 2분기 비율 → 도넛 차트 (원 + 가운데 원)
    • axes[1, 1]: 성장률 → 가로 막대 (양수/음수 색상 다르게)
  4. 성장률 계산:
    1
    
    df['성장률'] = (df['2분기'] - df['1분기']) / df['1분기'] * 100
    
  5. 마무리: plt.tight_layout()으로 간격 정리
정답 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

plt.rcParams['font.family'] = 'AppleGothic'

data = {
    '제품': ['노트북', '스마트폰', '태블릿', '이어폰'],
    '1분기': [100, 150, 80, 200],
    '2분기': [120, 160, 90, 220]
}
df = pd.DataFrame(data)

fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 1. 분기별 비교 (그룹 막대)
x = np.arange(len(df['제품']))
width = 0.35
axes[0, 0].bar(x - width/2, df['1분기'], width, label='1분기')
axes[0, 0].bar(x + width/2, df['2분기'], width, label='2분기')
axes[0, 0].set_xticks(x)
axes[0, 0].set_xticklabels(df['제품'])
axes[0, 0].set_title('분기별 제품 판매량')
axes[0, 0].legend()

# 2. 1분기 비율 (원 그래프)
axes[0, 1].pie(df['1분기'], labels=df['제품'], autopct='%1.1f%%')
axes[0, 1].set_title('1분기 판매 비율')

# 3. 2분기 비율 (도넛 차트)
axes[1, 0].pie(df['2분기'], labels=df['제품'], autopct='%1.1f%%')
centre = plt.Circle((0, 0), 0.5, fc='white')
axes[1, 0].add_patch(centre)
axes[1, 0].set_title('2분기 판매 비율')

# 4. 성장률 (가로 막대)
df['성장률'] = ((df['2분기'] - df['1분기']) / df['1분기'] * 100).round(1)
colors = ['green' if x > 0 else 'red' for x in df['성장률']]
axes[1, 1].barh(df['제품'], df['성장률'], color=colors)
axes[1, 1].set_title('제품별 성장률 (%)')
axes[1, 1].axvline(x=0, color='black', linewidth=0.5)

plt.tight_layout()
plt.show()

📝 오늘 배운 내용 정리

  1. 원/도넛 차트: plt.pie() - 비율 표현
  2. 히스토그램: plt.hist() - 분포 확인 (bins로 구간 설정)
  3. 산점도: plt.scatter() - 상관관계 분석
  4. Pandas 연동: df.plot(kind='...') - 간편한 시각화
  5. 대시보드: plt.subplots() - 여러 차트 조합

🔗 관련 자료


📚 이전 학습

Day 67: Matplotlib 기초 ⭐⭐

어제는 선 그래프, 막대 그래프와 기본 꾸미기를 배웠어요!

📚 다음 학습

Day 69: 데이터 분석 워크플로우 ⭐⭐⭐


“늦었다고 생각할 때가 가장 빠른 때입니다. 오늘도 한 걸음 성장했어요!” 🚀

Day 68/100 Phase 7: 데이터 분석 기초 #100DaysOfPython
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.