[Python 100일 챌린지] Day 70 - 미니 프로젝트: 데이터 분석 리포트
[Python 100일 챌린지] Day 70 - 미니 프로젝트: 데이터 분석 리포트
Phase 7 총정리! 실전 데이터 분석 프로젝트 🎯
NumPy, Pandas, Matplotlib 모두 활용해서 실제 데이터 분석 리포트를 만들어봅시다! 이것만 완성하면 데이터 분석 기초 완료! 🎉
(60분 완독 ⭐⭐⭐)
🎯 오늘의 학습 목표
📚 사전 지식
Phase 7에서 배운 모든 내용:
🎯 학습 목표 1: 프로젝트 소개 및 데이터 준비
1.1 프로젝트 개요
📊 “온라인 쇼핑몰 매출 분석 리포트”
가상의 온라인 쇼핑몰 데이터를 분석하여:
- 매출 현황 파악
- 고객 행동 분석
- 제품별 성과 분석
- 비즈니스 인사이트 도출
1.2 데이터 생성
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
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 재현 가능한 랜덤 시드
np.random.seed(42)
# 데이터 생성
n_orders = 500
# 날짜 생성 (2024년 1~6월)
start_date = datetime(2024, 1, 1)
dates = [start_date + timedelta(days=np.random.randint(0, 180)) for _ in range(n_orders)]
# 데이터프레임 생성
orders = pd.DataFrame({
'주문번호': [f'ORD{str(i).zfill(5)}' for i in range(1, n_orders + 1)],
'주문일': dates,
'고객ID': [f'C{np.random.randint(1, 101):03d}' for _ in range(n_orders)],
'제품': np.random.choice(['노트북', '스마트폰', '태블릿', '이어폰', '키보드'], n_orders),
'카테고리': np.random.choice(['전자기기', '악세서리'], n_orders, p=[0.6, 0.4]),
'수량': np.random.randint(1, 5, n_orders),
'단가': np.random.choice([50000, 100000, 200000, 500000, 1000000], n_orders),
'지역': np.random.choice(['서울', '경기', '부산', '대구', '인천'], n_orders),
'결제방법': np.random.choice(['카드', '계좌이체', '간편결제'], n_orders),
'고객등급': np.random.choice(['브론즈', '실버', '골드', 'VIP'], n_orders, p=[0.4, 0.3, 0.2, 0.1])
})
# 매출액 계산
orders['매출'] = orders['수량'] * orders['단가']
# 일부 결측값 추가 (현실적인 데이터)
orders.loc[np.random.choice(orders.index, 20), '지역'] = np.nan
orders.loc[np.random.choice(orders.index, 10), '고객등급'] = np.nan
print("=== 데이터 샘플 ===")
print(orders.head(10))
print(f"\n총 주문 건수: {len(orders)}")
1.3 데이터 저장 및 불러오기
1
2
3
4
5
6
7
# CSV로 저장
orders.to_csv('shopping_orders.csv', index=False, encoding='utf-8-sig')
print("데이터 저장 완료: shopping_orders.csv")
# 불러오기
df = pd.read_csv('shopping_orders.csv', parse_dates=['주문일'])
print(f"\n불러온 데이터: {df.shape[0]}행 x {df.shape[1]}열")
🎯 학습 목표 2: 데이터 정제 및 전처리
2.1 데이터 품질 확인
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
import pandas as pd
import numpy as np
# 데이터 불러오기 (위에서 생성한 orders 사용)
df = orders.copy()
print("=" * 50)
print(" 데이터 품질 점검 보고서")
print("=" * 50)
# 1. 기본 정보
print(f"\n📊 데이터 크기: {df.shape[0]}행 x {df.shape[1]}열")
print(f"📅 기간: {df['주문일'].min().date()} ~ {df['주문일'].max().date()}")
# 2. 결측값 확인
print("\n🔍 결측값 현황:")
missing = df.isnull().sum()
for col, count in missing[missing > 0].items():
print(f" - {col}: {count}개 ({count/len(df)*100:.1f}%)")
# 3. 중복 확인
duplicates = df.duplicated().sum()
print(f"\n🔄 중복 행: {duplicates}개")
# 4. 데이터 타입
print("\n📋 데이터 타입:")
print(df.dtypes)
2.2 결측값 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
df = orders.copy()
print("=== 결측값 처리 전 ===")
print(df.isnull().sum())
# 결측값 처리 전략
# 1. 지역: '미확인'으로 대체
df['지역'] = df['지역'].fillna('미확인')
# 2. 고객등급: '브론즈'(최저등급)로 대체
df['고객등급'] = df['고객등급'].fillna('브론즈')
print("\n=== 결측값 처리 후 ===")
print(df.isnull().sum())
2.3 파생 변수 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
df = orders.copy()
df['지역'] = df['지역'].fillna('미확인')
df['고객등급'] = df['고객등급'].fillna('브론즈')
# 날짜 관련 파생 변수
df['연월'] = df['주문일'].dt.to_period('M')
df['요일'] = df['주문일'].dt.day_name()
df['월'] = df['주문일'].dt.month
# 매출 구간
df['매출구간'] = pd.cut(df['매출'],
bins=[0, 100000, 500000, 1000000, float('inf')],
labels=['소액', '중간', '고액', '프리미엄'])
print("=== 파생 변수 추가 완료 ===")
print(df[['주문일', '연월', '요일', '월', '매출', '매출구간']].head())
🎯 학습 목표 3: 탐색적 데이터 분석
3.1 매출 현황 분석
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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
plt.rcParams['axes.unicode_minus'] = False
# 데이터 준비
df = orders.copy()
df['지역'] = df['지역'].fillna('미확인')
df['고객등급'] = df['고객등급'].fillna('브론즈')
df['연월'] = df['주문일'].dt.to_period('M')
df['월'] = df['주문일'].dt.month
print("=" * 50)
print(" 📊 매출 현황 분석")
print("=" * 50)
# 전체 요약
print(f"\n💰 총 매출: {df['매출'].sum():,}원")
print(f"📦 총 주문: {len(df):,}건")
print(f"📈 평균 주문금액: {df['매출'].mean():,.0f}원")
print(f"📊 중앙값: {df['매출'].median():,.0f}원")
# 월별 매출
print("\n=== 월별 매출 추이 ===")
monthly = df.groupby('월')['매출'].agg(['sum', 'count', 'mean'])
monthly.columns = ['총매출', '주문건수', '평균매출']
print(monthly)
3.2 매출 시각화
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
46
47
48
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
plt.rcParams['axes.unicode_minus'] = False
# 데이터 준비
np.random.seed(42)
df = orders.copy()
df['지역'] = df['지역'].fillna('미확인')
df['고객등급'] = df['고객등급'].fillna('브론즈')
df['연월'] = df['주문일'].dt.to_period('M')
df['월'] = df['주문일'].dt.month
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. 월별 매출 추이
monthly_sales = df.groupby('월')['매출'].sum()
axes[0, 0].plot(monthly_sales.index, monthly_sales.values / 1e6, 'bo-', linewidth=2)
axes[0, 0].set_title('월별 매출 추이', fontsize=14)
axes[0, 0].set_xlabel('월')
axes[0, 0].set_ylabel('매출 (백만원)')
axes[0, 0].grid(True, alpha=0.3)
# 2. 제품별 매출
product_sales = df.groupby('제품')['매출'].sum().sort_values(ascending=True)
colors = plt.cm.Blues(np.linspace(0.4, 0.8, len(product_sales)))
axes[0, 1].barh(product_sales.index, product_sales.values / 1e6, color=colors)
axes[0, 1].set_title('제품별 총 매출', fontsize=14)
axes[0, 1].set_xlabel('매출 (백만원)')
# 3. 지역별 매출 비율
region_sales = df.groupby('지역')['매출'].sum()
axes[1, 0].pie(region_sales, labels=region_sales.index, autopct='%1.1f%%',
colors=plt.cm.Pastel1(np.linspace(0, 1, len(region_sales))))
axes[1, 0].set_title('지역별 매출 비율', fontsize=14)
# 4. 결제방법별 매출
payment_sales = df.groupby('결제방법')['매출'].sum()
axes[1, 1].bar(payment_sales.index, payment_sales.values / 1e6,
color=['#FF6B6B', '#4ECDC4', '#45B7D1'])
axes[1, 1].set_title('결제방법별 매출', fontsize=14)
axes[1, 1].set_ylabel('매출 (백만원)')
plt.tight_layout()
plt.savefig('sales_analysis.png', dpi=150, bbox_inches='tight')
plt.show()
3.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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(42)
df = orders.copy()
df['지역'] = df['지역'].fillna('미확인')
df['고객등급'] = df['고객등급'].fillna('브론즈')
print("=" * 50)
print(" 👥 고객 분석")
print("=" * 50)
# 고객 수
unique_customers = df['고객ID'].nunique()
print(f"\n👤 총 고객 수: {unique_customers}명")
# 고객별 구매 현황
customer_stats = df.groupby('고객ID').agg({
'매출': ['sum', 'mean', 'count']
}).round(0)
customer_stats.columns = ['총구매액', '평균구매액', '구매횟수']
customer_stats = customer_stats.sort_values('총구매액', ascending=False)
print("\n=== 상위 10명 우수고객 ===")
print(customer_stats.head(10))
# 고객등급별 분석
grade_analysis = df.groupby('고객등급').agg({
'고객ID': 'nunique',
'매출': ['sum', 'mean']
})
grade_analysis.columns = ['고객수', '총매출', '평균매출']
grade_analysis = grade_analysis.round(0)
print("\n=== 고객등급별 현황 ===")
print(grade_analysis)
3.4 고객 시각화
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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(42)
df = orders.copy()
df['지역'] = df['지역'].fillna('미확인')
df['고객등급'] = df['고객등급'].fillna('브론즈')
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 등급별 고객 수
grade_order = ['VIP', '골드', '실버', '브론즈']
grade_counts = df.groupby('고객등급')['고객ID'].nunique()
grade_counts = grade_counts.reindex(grade_order)
colors = ['#FFD700', '#FFA500', '#C0C0C0', '#CD7F32']
axes[0].bar(grade_counts.index, grade_counts.values, color=colors)
axes[0].set_title('등급별 고객 수', fontsize=14)
axes[0].set_ylabel('고객 수')
# 등급별 평균 구매액
grade_avg = df.groupby('고객등급')['매출'].mean()
grade_avg = grade_avg.reindex(grade_order)
axes[1].bar(grade_avg.index, grade_avg.values / 10000, color=colors)
axes[1].set_title('등급별 평균 구매금액', fontsize=14)
axes[1].set_ylabel('금액 (만원)')
plt.tight_layout()
plt.savefig('customer_analysis.png', dpi=150, bbox_inches='tight')
plt.show()
🎯 학습 목표 4: 분석 리포트 완성
4.1 종합 대시보드
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(42)
df = orders.copy()
df['지역'] = df['지역'].fillna('미확인')
df['고객등급'] = df['고객등급'].fillna('브론즈')
df['월'] = df['주문일'].dt.month
# 대시보드 생성
fig = plt.figure(figsize=(16, 12))
# 1. 월별 매출 추이
ax1 = fig.add_subplot(2, 3, 1)
monthly = df.groupby('월')['매출'].sum() / 1e6
ax1.plot(monthly.index, monthly.values, 'b-o', linewidth=2)
ax1.fill_between(monthly.index, monthly.values, alpha=0.3)
ax1.set_title('📈 월별 매출 추이')
ax1.set_ylabel('매출 (백만원)')
ax1.grid(True, alpha=0.3)
# 2. 제품별 매출 TOP 5
ax2 = fig.add_subplot(2, 3, 2)
product = df.groupby('제품')['매출'].sum().sort_values()
ax2.barh(product.index, product.values / 1e6)
ax2.set_title('📦 제품별 매출')
ax2.set_xlabel('매출 (백만원)')
# 3. 지역별 매출
ax3 = fig.add_subplot(2, 3, 3)
region = df.groupby('지역')['매출'].sum()
ax3.pie(region, labels=region.index, autopct='%1.1f%%')
ax3.set_title('🗺️ 지역별 매출 비율')
# 4. 고객등급별 매출
ax4 = fig.add_subplot(2, 3, 4)
grade = df.groupby('고객등급')['매출'].sum()
grade_order = ['VIP', '골드', '실버', '브론즈']
grade = grade.reindex(grade_order)
colors = ['#FFD700', '#FFA500', '#C0C0C0', '#CD7F32']
ax4.bar(grade.index, grade.values / 1e6, color=colors)
ax4.set_title('👥 등급별 매출')
ax4.set_ylabel('매출 (백만원)')
# 5. 결제방법 분포
ax5 = fig.add_subplot(2, 3, 5)
payment = df['결제방법'].value_counts()
ax5.pie(payment, labels=payment.index, autopct='%1.1f%%',
colors=['#FF6B6B', '#4ECDC4', '#45B7D1'])
ax5.set_title('💳 결제방법 분포')
# 6. 주요 KPI
ax6 = fig.add_subplot(2, 3, 6)
ax6.axis('off')
kpi_text = f"""
═══════════════════════════════════
📊 주요 KPI 요약
═══════════════════════════════════
💰 총 매출: {df['매출'].sum():,}원
📦 총 주문: {len(df):,}건
👤 총 고객: {df['고객ID'].nunique()}명
📈 평균 주문금액: {df['매출'].mean():,.0f}원
🏆 최고 매출 제품: {df.groupby('제품')['매출'].sum().idxmax()}
🗺️ 최고 매출 지역: {df.groupby('지역')['매출'].sum().idxmax()}
═══════════════════════════════════
"""
ax6.text(0.1, 0.5, kpi_text, transform=ax6.transAxes,
fontsize=11, verticalalignment='center',
fontfamily='AppleGothic',
bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.5))
plt.suptitle('🛒 온라인 쇼핑몰 매출 분석 대시보드', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.savefig('dashboard_final.png', dpi=150, bbox_inches='tight')
plt.show()
4.2 인사이트 및 제언
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
46
47
import pandas as pd
import numpy as np
np.random.seed(42)
df = orders.copy()
df['지역'] = df['지역'].fillna('미확인')
df['고객등급'] = df['고객등급'].fillna('브론즈')
df['월'] = df['주문일'].dt.month
print("=" * 60)
print(" 📋 분석 결과 및 비즈니스 인사이트")
print("=" * 60)
# 1. 매출 분석 인사이트
monthly = df.groupby('월')['매출'].sum()
growth = (monthly.iloc[-1] - monthly.iloc[0]) / monthly.iloc[0] * 100
print("\n📈 매출 트렌드:")
print(f" • 분석 기간 매출 성장률: {growth:.1f}%")
print(f" • 최고 매출 월: {monthly.idxmax()}월 ({monthly.max():,}원)")
print(f" • 최저 매출 월: {monthly.idxmin()}월 ({monthly.min():,}원)")
# 2. 제품 분석 인사이트
product_sales = df.groupby('제품')['매출'].sum()
top_product = product_sales.idxmax()
bottom_product = product_sales.idxmin()
print("\n📦 제품 성과:")
print(f" • 베스트셀러: {top_product} ({product_sales[top_product]:,}원)")
print(f" • 개선 필요: {bottom_product} ({product_sales[bottom_product]:,}원)")
# 3. 고객 분석 인사이트
vip_ratio = len(df[df['고객등급'] == 'VIP']) / len(df) * 100
vip_sales_ratio = df[df['고객등급'] == 'VIP']['매출'].sum() / df['매출'].sum() * 100
print("\n👥 고객 인사이트:")
print(f" • VIP 고객 비율: {vip_ratio:.1f}%")
print(f" • VIP 매출 기여도: {vip_sales_ratio:.1f}%")
# 4. 제언
print("\n💡 비즈니스 제언:")
print(" 1. VIP 고객 리텐션 프로그램 강화 (매출 기여도 높음)")
print(f" 2. {bottom_product} 제품 마케팅 전략 재검토")
print(f" 3. {monthly.idxmin()}월 매출 부진 원인 분석 및 프로모션 검토")
print(" 4. 간편결제 사용 유도로 결제 편의성 향상")
print("\n" + "=" * 60)
💡 실전 팁
✅ 프로젝트 체크리스트
1
2
3
4
5
6
7
8
9
10
11
12
# 데이터 분석 프로젝트 완료 체크리스트
checklist = """
✅ 데이터 품질 점검 완료
✅ 결측값/이상치 처리 완료
✅ 파생 변수 생성 완료
✅ 기술 통계 분석 완료
✅ 시각화 대시보드 완성
✅ 인사이트 도출 완료
✅ 비즈니스 제언 작성 완료
✅ 분석 결과 저장 (PNG, CSV)
"""
print(checklist)
🧪 도전 과제
추가 분석 아이디어
- 시계열 분석: 요일별 매출 패턴 분석
- RFM 분석: 고객 세분화
- 코호트 분석: 월별 첫 구매 고객 추적
- 제품 연관 분석: 함께 구매되는 제품
📝 Phase 7 완료!
축하합니다! 🎉 Phase 7에서 배운 내용:
- NumPy: 배열 연산, 인덱싱, 슬라이싱
- Pandas: DataFrame, 데이터 로딩, 조작, 그룹화
- Matplotlib: 다양한 차트, 대시보드
- 데이터 분석: EDA, 워크플로우, 리포트
이제 실전 데이터 분석이 가능합니다! 🚀
📚 이전 학습
Day 69: 데이터 분석 워크플로우 ⭐⭐⭐
📚 다음 학습
Day 71: Phase 8 시작 - 데이터베이스와 SQL 소개 ⭐⭐
“Phase 7 완료! 데이터 분석의 기초를 마스터했습니다!” 🎊
Day 70/100 Phase 7: 데이터 분석 기초 완료 #100DaysOfPython
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
