[Python 100일 챌린지] Day 69 - 데이터 분석 워크플로우
[Python 100일 챌린지] Day 69 - 데이터 분석 워크플로우
실무 데이터 분석의 전체 흐름을 배워봅시다! 🔄
데이터 수집 → 정제 → 분석 → 시각화 → 인사이트 실제 분석가들이 일하는 방식을 그대로! 이 흐름만 알면 어떤 데이터든 분석할 수 있어요! 💪
(40분 완독 ⭐⭐⭐)
🎯 오늘의 학습 목표
📚 사전 지식
- Day 63: Pandas 기초 - DataFrame 기본
- Day 65: Pandas 데이터 조작 - 필터링, 정렬
- Day 66: Pandas 그룹화와 집계 - groupby
- Day 67: Matplotlib 기초 - 시각화
🎯 학습 목표 1: 데이터 분석 프로세스 이해하기
1.1 분석 프로세스 개요
graph LR
A[1. 문제 정의] --> B[2. 데이터 수집]
B --> C[3. 데이터 정제]
C --> D[4. 탐색적 분석]
D --> E[5. 심층 분석]
E --> F[6. 시각화/보고]
1.2 각 단계 설명
| 단계 | 목적 | 주요 작업 |
|---|---|---|
| 문제 정의 | 분석 목표 설정 | 질문 정의, KPI 설정 |
| 데이터 수집 | 원천 데이터 확보 | CSV, DB, API |
| 데이터 정제 | 품질 향상 | 결측값, 이상치 처리 |
| 탐색적 분석 | 데이터 이해 | 기술 통계, 분포 확인 |
| 심층 분석 | 인사이트 도출 | 그룹 분석, 상관 분석 |
| 시각화/보고 | 결과 전달 | 차트, 리포트 |
1.3 분석 질문 예시
1
2
3
4
5
6
7
8
# 좋은 분석 질문의 예시
questions = [
"어떤 제품이 가장 많이 팔리나?",
"매출이 증가하는 추세인가?",
"어떤 고객층이 주요 타겟인가?",
"어떤 요인이 매출에 영향을 미치나?",
"이탈 위험이 있는 고객은 누구인가?"
]
🎯 학습 목표 2: 탐색적 데이터 분석(EDA) 배우기
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
28
import pandas as pd
import numpy as np
# 샘플 데이터 생성
np.random.seed(42)
df = pd.DataFrame({
'고객ID': range(1, 101),
'나이': np.random.randint(20, 60, 100),
'성별': np.random.choice(['남', '여'], 100),
'구매금액': np.random.randint(10000, 100000, 100),
'구매횟수': np.random.randint(1, 20, 100),
'등급': np.random.choice(['브론즈', '실버', '골드'], 100)
})
# 1. 데이터 크기
print(f"행: {df.shape[0]}, 열: {df.shape[1]}")
# 2. 데이터 타입
print("\n=== 데이터 타입 ===")
print(df.dtypes)
# 3. 기본 정보
print("\n=== 기본 정보 ===")
print(df.info())
# 4. 처음/끝 확인
print("\n=== 처음 5행 ===")
print(df.head())
2.2 기술 통계량 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({
'나이': np.random.randint(20, 60, 100),
'구매금액': np.random.randint(10000, 100000, 100),
'구매횟수': np.random.randint(1, 20, 100)
})
# 수치형 변수 요약
print("=== 기술 통계량 ===")
print(df.describe())
# 개별 통계
print(f"\n평균 구매금액: {df['구매금액'].mean():,.0f}원")
print(f"중앙값: {df['구매금액'].median():,.0f}원")
print(f"표준편차: {df['구매금액'].std():,.0f}원")
2.3 범주형 변수 분석
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({
'성별': np.random.choice(['남', '여'], 100),
'등급': np.random.choice(['브론즈', '실버', '골드'], 100)
})
# 빈도수 확인
print("=== 성별 분포 ===")
print(df['성별'].value_counts())
print("\n=== 등급 분포 ===")
print(df['등급'].value_counts())
# 비율 확인
print("\n=== 등급 비율 ===")
print(df['등급'].value_counts(normalize=True).round(3) * 100)
2.4 EDA 시각화
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
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 = pd.DataFrame({
'나이': np.random.randint(20, 60, 100),
'구매금액': np.random.randint(10000, 100000, 100),
'등급': np.random.choice(['브론즈', '실버', '골드'], 100)
})
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 1. 나이 분포
axes[0, 0].hist(df['나이'], bins=15, edgecolor='black')
axes[0, 0].set_title('나이 분포')
axes[0, 0].set_xlabel('나이')
# 2. 구매금액 분포
axes[0, 1].hist(df['구매금액'], bins=15, edgecolor='black')
axes[0, 1].set_title('구매금액 분포')
axes[0, 1].set_xlabel('금액')
# 3. 등급별 비율
grade_counts = df['등급'].value_counts()
axes[1, 0].pie(grade_counts, labels=grade_counts.index, autopct='%1.1f%%')
axes[1, 0].set_title('등급 비율')
# 4. 등급별 평균 구매금액
grade_avg = df.groupby('등급')['구매금액'].mean()
axes[1, 1].bar(grade_avg.index, grade_avg.values)
axes[1, 1].set_title('등급별 평균 구매금액')
axes[1, 1].set_ylabel('금액')
plt.tight_layout()
plt.show()
🎯 학습 목표 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
30
import pandas as pd
import numpy as np
# 결측값이 있는 데이터
df = pd.DataFrame({
'이름': ['철수', '영희', '민수', None, '지영'],
'나이': [25, None, 30, 28, None],
'구매금액': [50000, 30000, None, 45000, 35000]
})
print("=== 원본 데이터 ===")
print(df)
# 1. 결측값 확인
print("\n=== 결측값 개수 ===")
print(df.isnull().sum())
# 2. 결측값 처리 전략
# 방법 1: 삭제
df_dropped = df.dropna()
print("\n=== 결측값 삭제 후 ===")
print(df_dropped)
# 방법 2: 대체
df_filled = df.copy()
df_filled['나이'] = df_filled['나이'].fillna(df_filled['나이'].mean())
df_filled['구매금액'] = df_filled['구매금액'].fillna(df_filled['구매금액'].median())
df_filled['이름'] = df_filled['이름'].fillna('미상')
print("\n=== 결측값 대체 후 ===")
print(df_filled)
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
import pandas as pd
import numpy as np
np.random.seed(42)
# 이상치가 포함된 데이터
df = pd.DataFrame({
'구매금액': [50000, 45000, 55000, 48000, 52000,
500000, # 이상치!
49000, 51000, 47000, 46000]
})
print("=== 기술 통계 ===")
print(df.describe())
# IQR 방식으로 이상치 탐지
Q1 = df['구매금액'].quantile(0.25)
Q3 = df['구매금액'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
print(f"\n정상 범위: {lower:,.0f} ~ {upper:,.0f}")
# 이상치 필터링
outliers = df[(df['구매금액'] < lower) | (df['구매금액'] > upper)]
print(f"\n이상치 개수: {len(outliers)}")
print(outliers)
# 이상치 제거
df_clean = df[(df['구매금액'] >= lower) & (df['구매금액'] <= upper)]
print(f"\n정제 후 데이터 수: {len(df_clean)}")
3.3 데이터 타입 변환
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
df = pd.DataFrame({
'날짜': ['2024-01-01', '2024-01-02', '2024-01-03'],
'금액': ['10,000', '20,000', '15,000'],
'수량': ['5', '3', '8']
})
print("=== 변환 전 ===")
print(df.dtypes)
# 날짜 변환
df['날짜'] = pd.to_datetime(df['날짜'])
# 숫자 변환 (쉼표 제거 후)
df['금액'] = df['금액'].str.replace(',', '').astype(int)
df['수량'] = df['수량'].astype(int)
print("\n=== 변환 후 ===")
print(df.dtypes)
print(df)
🎯 학습 목표 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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
np.random.seed(42)
df = pd.DataFrame({
'나이': np.random.randint(20, 60, 100),
'구매금액': np.random.randint(10000, 100000, 100),
'구매횟수': np.random.randint(1, 20, 100),
'방문횟수': np.random.randint(1, 30, 100)
})
# 상관계수 계산
correlation = df.corr()
print("=== 상관계수 ===")
print(correlation.round(2))
# 히트맵으로 시각화
fig, ax = plt.subplots(figsize=(8, 6))
im = ax.imshow(correlation, cmap='coolwarm', aspect='auto')
ax.set_xticks(range(len(correlation.columns)))
ax.set_yticks(range(len(correlation.columns)))
ax.set_xticklabels(correlation.columns)
ax.set_yticklabels(correlation.columns)
# 값 표시
for i in range(len(correlation)):
for j in range(len(correlation)):
ax.text(j, i, f'{correlation.iloc[i, j]:.2f}',
ha='center', va='center')
plt.colorbar(im)
plt.title('상관관계 히트맵')
plt.tight_layout()
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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
np.random.seed(42)
df = pd.DataFrame({
'등급': np.random.choice(['브론즈', '실버', '골드'], 100),
'구매금액': np.random.randint(10000, 100000, 100),
'구매횟수': np.random.randint(1, 20, 100)
})
# 등급별 분석
grade_analysis = df.groupby('등급').agg({
'구매금액': ['mean', 'sum', 'count'],
'구매횟수': 'mean'
}).round(0)
print("=== 등급별 분석 ===")
print(grade_analysis)
# 시각화
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
grade_mean = df.groupby('등급')['구매금액'].mean()
grade_mean.plot(kind='bar', ax=axes[0], color=['#CD7F32', '#C0C0C0', '#FFD700'])
axes[0].set_title('등급별 평균 구매금액')
axes[0].set_ylabel('금액')
axes[0].tick_params(axis='x', rotation=0)
grade_count = df.groupby('등급')['구매금액'].count()
grade_count.plot(kind='bar', ax=axes[1], color=['#CD7F32', '#C0C0C0', '#FFD700'])
axes[1].set_title('등급별 고객 수')
axes[1].set_ylabel('명')
axes[1].tick_params(axis='x', rotation=0)
plt.tight_layout()
plt.show()
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
import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({
'등급': np.random.choice(['브론즈', '실버', '골드'], 100),
'구매금액': np.random.randint(10000, 100000, 100),
'구매횟수': np.random.randint(1, 20, 100)
})
# 분석 결과 요약
print("=" * 50)
print(" 고객 데이터 분석 보고서")
print("=" * 50)
print(f"\n📊 전체 고객 수: {len(df):,}명")
print(f"💰 총 매출: {df['구매금액'].sum():,}원")
print(f"📈 평균 구매금액: {df['구매금액'].mean():,.0f}원")
print("\n🏆 등급별 현황:")
grade_stats = df.groupby('등급').agg({
'구매금액': ['count', 'mean', 'sum']
})
for grade in ['골드', '실버', '브론즈']:
if grade in grade_stats.index:
count = grade_stats.loc[grade, ('구매금액', 'count')]
avg = grade_stats.loc[grade, ('구매금액', 'mean')]
total = grade_stats.loc[grade, ('구매금액', 'sum')]
print(f" - {grade}: {count}명, 평균 {avg:,.0f}원, 합계 {total:,}원")
print("\n💡 인사이트:")
print(" 1. 골드 등급 고객의 구매력이 가장 높음")
print(" 2. 브론즈 고객 업그레이드 프로모션 권장")
print(" 3. 충성 고객 리텐션 프로그램 필요")
print("\n" + "=" * 50)
💡 실전 팁
✅ EDA 체크리스트
1
2
3
4
5
6
7
8
# 데이터 분석 시작할 때 항상 확인!
def eda_checklist(df):
print("1. 데이터 크기:", df.shape)
print("2. 컬럼:", df.columns.tolist())
print("3. 데이터 타입:\n", df.dtypes)
print("4. 결측값:\n", df.isnull().sum())
print("5. 기술 통계:\n", df.describe())
print("6. 중복 행:", df.duplicated().sum())
🧪 연습 문제
문제: 판매 데이터 종합 분석
다음 데이터로 완전한 EDA를 수행하세요.
1
2
3
4
5
6
7
sales = pd.DataFrame({
'날짜': pd.date_range('2024-01-01', periods=100),
'제품': np.random.choice(['A', 'B', 'C'], 100),
'지역': np.random.choice(['서울', '부산', '대구'], 100),
'판매량': np.random.randint(10, 100, 100),
'매출': np.random.randint(100000, 1000000, 100)
})
✅ 정답 코드
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
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)
sales = pd.DataFrame({
'날짜': pd.date_range('2024-01-01', periods=100),
'제품': np.random.choice(['A', 'B', 'C'], 100),
'지역': np.random.choice(['서울', '부산', '대구'], 100),
'판매량': np.random.randint(10, 100, 100),
'매출': np.random.randint(100000, 1000000, 100)
})
# 1. 기본 정보
print("=== 데이터 기본 정보 ===")
print(f"행: {sales.shape[0]}, 열: {sales.shape[1]}")
print(f"기간: {sales['날짜'].min()} ~ {sales['날짜'].max()}")
# 2. 기술 통계
print("\n=== 기술 통계 ===")
print(sales.describe())
# 3. 제품별 분석
print("\n=== 제품별 분석 ===")
print(sales.groupby('제품').agg({
'판매량': ['sum', 'mean'],
'매출': ['sum', 'mean']
}))
# 4. 시각화
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 일별 매출 추이
daily = sales.groupby('날짜')['매출'].sum()
axes[0, 0].plot(daily.index, daily.values)
axes[0, 0].set_title('일별 매출 추이')
# 제품별 매출
prod_sales = sales.groupby('제품')['매출'].sum()
axes[0, 1].bar(prod_sales.index, prod_sales.values)
axes[0, 1].set_title('제품별 총 매출')
# 지역별 비율
region_sales = sales.groupby('지역')['매출'].sum()
axes[1, 0].pie(region_sales, labels=region_sales.index, autopct='%1.1f%%')
axes[1, 0].set_title('지역별 매출 비율')
# 판매량 분포
axes[1, 1].hist(sales['판매량'], bins=15, edgecolor='black')
axes[1, 1].set_title('판매량 분포')
plt.tight_layout()
plt.show()
# 5. 인사이트
print("\n=== 인사이트 ===")
best_product = prod_sales.idxmax()
best_region = region_sales.idxmax()
print(f"1. 최고 매출 제품: {best_product}")
print(f"2. 최고 매출 지역: {best_region}")
📝 오늘 배운 내용 정리
- 분석 프로세스: 문제정의 → 수집 → 정제 → 분석 → 보고
- EDA: 기술통계, 분포, 상관관계 확인
- 데이터 정제: 결측값, 이상치, 타입 변환
- 결과 해석: 상관분석, 그룹비교, 인사이트 도출
📚 이전 학습
Day 68: 데이터 시각화 실전 ⭐⭐
📚 다음 학습
Day 70: 미니 프로젝트: 데이터 분석 리포트 ⭐⭐⭐
“체계적인 분석 프로세스가 좋은 인사이트를 만든다!” 🔄
Day 69/100 Phase 7: 데이터 분석 기초 #100DaysOfPython
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
