포스트

[Python 100일 챌린지] Day 69 - 데이터 분석 워크플로우

[Python 100일 챌린지] Day 69 - 데이터 분석 워크플로우

실무 데이터 분석의 전체 흐름을 배워봅시다! 🔄

데이터 수집 → 정제 → 분석 → 시각화 → 인사이트 실제 분석가들이 일하는 방식을 그대로! 이 흐름만 알면 어떤 데이터든 분석할 수 있어요! 💪

(40분 완독 ⭐⭐⭐)

🎯 오늘의 학습 목표

📚 사전 지식


🎯 학습 목표 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}")

📝 오늘 배운 내용 정리

  1. 분석 프로세스: 문제정의 → 수집 → 정제 → 분석 → 보고
  2. EDA: 기술통계, 분포, 상관관계 확인
  3. 데이터 정제: 결측값, 이상치, 타입 변환
  4. 결과 해석: 상관분석, 그룹비교, 인사이트 도출

📚 이전 학습

Day 68: 데이터 시각화 실전 ⭐⭐

📚 다음 학습

Day 70: 미니 프로젝트: 데이터 분석 리포트 ⭐⭐⭐


“체계적인 분석 프로세스가 좋은 인사이트를 만든다!” 🔄

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