# Part 6: 머신러닝 모델링과 평가

**⬅️ 이전 시간: [Part 5: AI 핵심 라이브러리](../05_ai_core_libraries/part_5_ai_core_libraries.md)**
**➡️ 다음 시간: [Part 7: 딥러닝 기초와 PyTorch](../07_deep_learning/part_7_deep_learning.md)**

---

## 1. 학습 목표 (Learning Objectives)

이번 파트가 끝나면, 여러분은 다음을 할 수 있게 됩니다.

- Matplotlib와 Seaborn을 사용하여 데이터의 분포, 관계, 추세를 시각화하고 인사이트를 도출할 수 있습니다.
- 지도학습, 훈련/테스트 데이터 분할의 개념을 설명할 수 있습니다.
- Scikit-learn의 `fit()`, `predict()` 인터페이스를 사용하여 머신러닝 모델을 훈련하고, 새로운 데이터에 대한 예측을 만들 수 있습니다.
- 피처 스케일링(StandardScaler, MinMaxScaler)과 같은 핵심 전처리 기법을 모델 성능 향상을 위해 적용할 수 있습니다.
- 데이터 불러오기부터 전처리, 훈련, 평가까지 이어지는 머신러닝의 전체 파이프라인을 코드로 구현할 수 있습니다.

## 2. 핵심 요약 (Key Summary)
이 파트에서는 데이터에서 패턴을 발견하고 미래를 예측하는 머신러닝의 전 과정을 학습합니다. Matplotlib와 Seaborn을 이용한 데이터 시각화로 숨겨진 인사이트를 찾는 법을 배우고, Scikit-learn 라이브러리를 통해 지도학습의 기본 개념과 모델 훈련/평가 프로세스를 익힙니다. 훈련/테스트 데이터 분리, 피처 스케일링 등 핵심적인 데이터 전처리 기법을 적용하여 모델의 성능을 향상시키는 방법을 실습하며, 머신러닝 프로젝트의 전체 파이프라인을 직접 구축해 봅니다.

- **핵심 키워드**: `데이터 시각화`, `Matplotlib`, `Seaborn`, `Scikit-learn`, `지도학습(Supervised Learning)`, `훈련/테스트 분리(Train/Test Split)`, `데이터 전처리(Preprocessing)`, `피처 스케일링(Feature Scaling)`, `모델 평가(Evaluation)`, `정확도(Accuracy)`

## 3. 도입: 데이터에서 지혜를 캐내는 기술 (Introduction)

이전 파트에서 우리는 NumPy와 Pandas로 데이터를 자유자재로 다루는 법을 배웠습니다. 하지만 숫자로만 가득한 표는 우리에게 많은 것을 알려주지 않습니다. 이번 파트에서는 데이터에 '생명'을 불어넣는 두 가지 핵심 기술, **시각화**와 **머신러닝**을 배웁니다.

- **시각화**는 데이터 속에 숨겨진 패턴과 이야기를 발견하는 '눈'이 되어줄 것입니다.
- **머신러닝**은 그 패턴을 학습하여 미래를 예측하는 '두뇌' 역할을 합니다.

Scikit-learn이라는 강력한 도구를 통해, 우리는 이 모든 과정을 직접 체험해볼 것입니다.

> [!TIP]
> 본 파트의 모든 예제 코드는 `../../source_code/part_6_machine_learning.py` 파일에서 직접 실행하고 수정해볼 수 있습니다.

---

## 4. 데이터 시각화: 그림으로 데이터와 대화하기

> **🎯 1-2일차 목표:** Matplotlib와 Seaborn으로 데이터를 시각화하여 인사이트를 발견합니다.

데이터를 숫자로만 보는 것은 숲을 보지 못하고 나무만 보는 것과 같습니다. 시각화는 데이터 속에 숨겨진 패턴, 관계, 이상치를 한눈에 파악하게 해주는 강력한 도구입니다.

- **Matplotlib**: 파이썬 시각화의 근간. 거의 모든 종류의 그래프를 그릴 수 있습니다. (비유: 하얀 도화지)
- **Seaborn**: Matplotlib을 더 쉽고 예쁘게 사용하도록 만든 고수준 라이브러리. 통계 기능이 특화되어 있습니다. (비유: 밑그림과 색칠 도구가 갖춰진 스케치북)

#### 4-1. 어떤 그래프를 언제 쓸까?
- **선 그래프 (Line Plot)**: 시간에 따른 주가 변화처럼, 연속적인 데이터의 **추세**를 볼 때
- **막대 그래프 (Bar Plot)**: 반별 평균 키처럼, 여러 그룹 간의 값을 **비교**할 때
- **산점도 (Scatter Plot)**: 공부 시간과 성적처럼, 두 변수 간의 **관계**나 분포를 볼 때
- **히스토그램 (Histogram)**: 우리 반 학생들의 키 분포처럼, 데이터의 **분포**를 볼 때
- **히트맵 (Heatmap)**: 여러 변수들 간의 상관관계를 한눈에 **색상**으로 파악할 때

#### 4-2. Seaborn 실전 예제
```python
import matplotlib.pyplot as plt
import seaborn as sns

# Seaborn에 내장된 'tips' 데이터셋 사용
tips = sns.load_dataset("tips")

# 1. 산점도: 총 식사 금액과 팁 사이의 관계
plt.figure(figsize=(8, 6))
sns.scatterplot(x="total_bill", y="tip", data=tips, hue="smoker", size="size")
plt.title("Total Bill vs Tip Amount")
plt.xlabel("Total Bill ($)")
plt.ylabel("Tip ($)")
plt.grid(True)
plt.show()

# 2. 막대 그래프: 요일별 평균 팁
plt.figure(figsize=(8, 6))
sns.barplot(x="day", y="tip", data=tips, errorbar=None) # errorbar=None은 신뢰구간 제거
plt.title("Average Tip by Day of the Week")
plt.show()
```

---

## 5. Scikit-learn으로 첫 머신러닝 모델 만들기

> **🎯 3-4일차 목표:** Scikit-learn을 사용하여 머신러닝의 기본 프로세스(학습, 예측, 평가)를 이해합니다.

### 5-1. 머신러닝의 핵심: 훈련과 시험
- **지도학습(Supervised Learning)**: **입력(문제)**과 **정답**이 있는 데이터를 사용해, 문제와 정답 사이의 '패턴'을 기계에 학습시키는 방법입니다.

> **💡 비유: 머신러닝은 '공부'와 '시험' 과정입니다.**
> - **훈련 데이터 (Training Data)**: 모델이 학습하는 데 사용하는 **'교과서/모의고사'**.
> - **테스트 데이터 (Test Data)**: 모델의 최종 성능을 평가하기 위해, 학습 과정에서 **전혀 사용하지 않은 새로운 '수능 문제'**.
>
> 훈련 데이터로만 반복해서 시험 보면 100점이 나오겠지만, 진짜 실력이라고 할 수 없겠죠? 그래서 우리는 훈련/테스트 데이터를 엄격히 분리하여 모델의 **일반화 성능**(처음 보는 데이터에 대한 예측 능력)을 측정합니다.

### 5-2. Scikit-learn 기본 4단계 프로세스
Scikit-learn은 다음과 같은 통일된 인터페이스를 제공하여 누구나 쉽게 머신러닝 모델을 만들 수 있게 해줍니다.

1.  **모델 객체 생성**: `model = ModelName()`
2.  **모델 학습**: `model.fit(X_train, y_train)` (훈련 데이터로 공부)
3.  **예측**: `predictions = model.predict(X_test)` (테스트 데이터로 시험)
4.  **평가**: `score = accuracy_score(y_test, predictions)` (채점)

```python
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
import seaborn as sns
import numpy as np

# 데이터 로드 (붓꽃 데이터)
iris = sns.load_dataset("iris")
X, y = iris.drop("species", axis=1), iris["species"]

# 1. 데이터 분리 (훈련 80%, 테스트 20%)
# stratify=y : 훈련/테스트 데이터의 클래스 비율을 원본과 동일하게 유지
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# 2. 모델 생성 및 학습
model = DecisionTreeClassifier(random_state=42)
model.fit(X_train, y_train)

# 3. 예측
predictions = model.predict(X_test)

# 4. 평가 (정확도)
accuracy = accuracy_score(y_test, predictions)
print(f"정확도: {accuracy:.4f}")
```

### 5-3. 모델 성능을 높이는 데이터 전처리
모델의 성능은 알고리즘만큼이나 **'데이터의 품질'**에 크게 좌우됩니다. "Garbage In, Garbage Out" (쓰레기를 넣으면 쓰레기가 나온다) 라는 말이 있을 정도입니다.

- **피처 스케일링(Feature Scaling)**: 변수들의 단위를 맞춰줍니다. (예: 키(cm)와 몸무게(kg) -> 0~1 사이 값으로 표준화)
    - **StandardScaler**: 평균 0, 표준편차 1로 변환. (분포가 정규분포에 가까울 때 효과적)
    - **MinMaxScaler**: 최솟값 0, 최댓값 1로 변환. (모든 값을 0과 1 사이로 만들고 싶을 때)

> **💡 스케일러의 수학적 원리**
> 
> - **StandardScaler (표준화)**: 각 특성의 평균(μ)을 0, 표준편차(σ)를 1로 만듭니다.
>   \[ z = \frac{x - \mu}{\sigma} \]
>   이는 데이터의 분포를 정규분포와 유사하게 만들어, 거리 기반 알고리즘(e.g., SVM, 로지스틱 회귀)이나 경사 하강법을 사용하는 모델의 성능을 향상시키는 데 도움을 줍니다.
> 
> - **MinMaxScaler (정규화)**: 각 특성의 모든 값을 0과 1 사이로 조정합니다.
>   \[ x' = \frac{x - \min(x)}{\max(x) - \min(x)} \]
>   이미지 픽셀 값을 0~255에서 0~1 사이로 변환하거나, 신경망 모델의 입력으로 사용할 때 자주 사용됩니다.

```python
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import numpy as np

data = np.array([[170, 70], [180, 85], [160, 55]], dtype=float)

scaler_std = StandardScaler()
scaled_std = scaler_std.fit_transform(data)
print("StandardScaler 결과:\n", scaled_std)

scaler_minmax = MinMaxScaler()
scaled_minmax = scaler_minmax.fit_transform(data)
print("\nMinMaxScaler 결과:\n", scaled_minmax)
```

### 5-4. 심화: 어떤 모델을 언제 사용해야 할까? (Model Selection Guide)

Scikit-learn에는 수많은 머신러닝 모델이 존재합니다. 문제의 종류, 데이터의 특성, 그리고 우리가 추구하는 목표(성능, 해석 가능성, 속도 등)에 따라 최적의 모델은 달라집니다. 여기서는 가장 대표적인 **분류(Classification)** 모델 몇 가지를 비교하고, 언제 어떤 모델을 선택하는 것이 좋은지에 대한 가이드라인을 제시합니다.

| 모델 | 핵심 아이디어 | 장점 | 단점 | 언제 사용하면 좋을까? |
| :--- | :--- | :--- | :--- | :--- |
| **로지스틱 회귀<br>(Logistic Regression)** | 데이터가 특정 클래스에 속할 확률을 선형 결정 경계로 예측 | 빠르고, 간단하며, **해석이 용이함**. 모델의 계수가 각 특성의 중요도를 나타냄. | 복잡한 비선형 관계를 학습하기 어려움. | **모델의 해석**이 중요할 때 (e.g., 금융, 의료), 베이스라인 모델로 사용하기 좋음. |
| **결정 트리<br>(Decision Tree)** | 데이터를 '예/아니오' 질문(규칙)의 연속으로 나누어 예측 | **결과를 이해하기 쉬움 (White Box)**. 시각화가 가능함. 스케일링이 필요 없음. | **과적합(Overfitting) 위험이 높음**. 데이터의 작은 변화에도 모델이 크게 변동될 수 있음. | 규칙 기반으로 데이터를 설명하고 싶을 때. (e.g., 고객 이탈 원인 분석) |
| **랜덤 포레스트<br>(Random Forest)** | 여러 개의 작은 결정 트리들을 만들어, 그 결과를 **투표(Voting)**하여 종합. (앙상블 기법) | **성능이 매우 우수함**. 과적합에 강하고 안정적임. | 결정 트리보다 **해석이 어려움 (Black Box)**. 훈련 속도가 느리고 메모리를 더 많이 사용. | **높은 예측 성능**이 가장 중요할 때. 대부분의 분류 문제에서 좋은 성능을 보임. |
| **서포트 벡터 머신<br>(SVM)** | 클래스 간의 **마진(Margin)을 최대화**하는 결정 경계를 찾음. | 고차원 데이터에서 잘 작동하며, 과적합에 강함. | 데이터가 많을 때 훈련 속도가 매우 느림. 파라미터 튜닝에 민감함. | 특성(Feature)이 매우 많은 복잡한 데이터셋 (e.g., 이미지, 바이오인포매틱스)에 효과적. |

> **💡 핵심 질문: 해석 가능성(Interpretability) vs. 성능(Performance)**
> - **해석이 중요하다면?** -> Logistic Regression, Decision Tree
> - **성능이 중요하다면?** -> Random Forest, Gradient Boosting (더 발전된 앙상블), SVM
>
> 실무에서는 먼저 Logistic Regression이나 Decision Tree 같은 간단한 모델로 베이스라인을 설정하고, 점차 Random Forest나 Gradient Boosting과 같은 복잡한 모델로 성능을 높여가는 방식을 많이 사용합니다.

이 가이드는 시작점일 뿐이며, 최고의 모델을 찾는 유일한 방법은 **직접 여러 모델을 실험해보고, 교차 검증(Cross-validation)을 통해 성능을 객관적으로 평가하는 것**입니다.

### 5-5. 실제 기업 적용 사례 (Real-world Enterprise Use Cases)

우리가 배운 머신러닝 기술은 단순히 학문적인 개념에 머무르지 않고, 오늘날 수많은 글로벌 기업들의 핵심 서비스를 구동하는 엔진이 되고 있습니다. 몇 가지 대표적인 사례를 통해 머신러닝이 실제로 어떻게 가치를 창출하는지 살펴보겠습니다.

| 기업 | 적용 분야 | 사용 기술 및 모델 (추정) | 비즈니스 가치 |
| :--- | :--- | :--- | :--- |
| **Netflix** | **영화/드라마 추천 시스템** | 협업 필터링, 콘텐츠 기반 필터링, 랭킹 알고리즘 (e.g., Logistic Regression, Gradient Boosting) | 개인화된 콘텐츠 추천을 통해 **고객 이탈률을 낮추고**, 사용자 만족도를 극대화. (매년 1조 원 이상의 가치 창출) |
| **Google** | **Gmail 스팸 필터** | 지도 학습 분류기 (e.g., Naive Bayes, Logistic Regression), 딥러닝(RNN, Transformer) | 매일 수십억 개의 스팸 메일을 99.9% 이상의 정확도로 차단하여, **사용자 경험을 보호**하고 보안 위협을 감소시킴. |
| **Google** | **검색 결과 랭킹 (RankBrain)** | 학습-투-랭크(Learning to Rank) 알고리즘 | 이전에는 없었던 새로운 검색어(전체 검색의 15%)에 대해 **가장 관련성 높은 결과를 추론**하여 제시. 검색 품질 향상. |
| **Meta (Facebook)** | **뉴스피드 랭킹** | 랭킹 알고리즘, 대규모 추천 시스템 | 수천 개의 잠재적 게시물 중 사용자에게 가장 흥미로울 만한 콘텐츠를 예측하여 보여줌으로써, **플랫폼 체류 시간을 늘리고** 광고 효율을 높임. |
| **Amazon** | **상품 추천 (Customers who bought this item also bought...)** | 협업 필터링 (Item-to-Item), 개인화 랭킹 | 사용자의 구매 패턴을 분석하여 관련 상품을 추천함으로써, **객단가(Average Order Value)를 높이고** 새로운 상품을 발견할 기회를 제공. |

> **💡 시사점: 문제 정의의 중요성**
> 위 사례들의 공통점은 기술 자체가 목적이 아니라, '고객 이탈 방지', '사용자 경험 보호', '관련성 높은 정보 제공'과 같은 **명확한 비즈니스 문제를 해결하기 위해 머신러닝을 '도구'로 사용했다는 점**입니다. 성공적인 머신러닝 프로젝트를 위해서는 "어떤 모델을 쓸까?" 보다 "**어떤 문제를 풀고 싶은가?**"를 먼저 정의하는 것이 중요합니다.

---

## 6. 연습 문제: 타이타닉 생존자 예측

> **🎯 5일차 목표:** 데이터 전처리, 시각화, 모델링, 평가의 전 과정을 종합하여 문제를 해결합니다.

고전적인 '타이타닉' 데이터셋을 사용하여, 어떤 승객이 생존했을지 예측하는 모델을 만들어 봅시다.

### 문제:
1.  Seaborn에서 `titanic` 데이터셋을 불러옵니다.
2.  간단한 탐색적 데이터 분석(EDA)을 수행하세요. (`survived`와 `pclass`, `sex` 간의 관계를 막대 그래프로 시각화)
3.  모델링에 사용할 특성(`features`)으로 `pclass`, `sex`, `age`, `sibsp`, `parch`, `fare`를, 타겟(`target`)으로 `survived`를 선택하세요.
4.  결측치가 있는 `age` 열을 `age` 열의 **중앙값(median)**으로 채워주세요.
5.  `sex` 열의 문자열('male', 'female')을 숫자(0, 1)로 변환해주세요.
6.  데이터를 훈련/테스트 세트로 분리하고 `StandardScaler`를 적용하여 스케일링하세요.
7.  `DecisionTreeClassifier`로 모델을 학습시키고, 테스트 데이터에 대한 **정확도**를 계산하세요.

---

## 7. 심화 토론: 무엇이 잘못될 수 있을까?

Scikit-learn을 사용하면 몇 줄의 코드로 쉽게 모델을 만들 수 있지만, 그 과정에는 수많은 함정이 존재합니다. "동작하는" 코드를 넘어 "올바른" 코드를 작성하기 위해 다음 주제들에 대해 함께 토론해보세요.

1.  **전처리 순서가 초래한 데이터 누수(Data Leakage)**
    -   **상황**: 한 동료가 효율성을 위해 전체 데이터셋 `X`에 대해 `StandardScaler`를 먼저 적용(`fit_transform`)한 후, 그 결과를 `train_test_split`으로 나누어 모델을 학습시켰습니다. 코드는 오류 없이 잘 동작했고, 테스트 정확도도 꽤 높게 나왔습니다.
    -   **토론**:
        -   이 접근 방식의 무엇이 치명적인 실수일까요? 테스트셋의 정보가 훈련 과정에 어떻게 "누수"되었을까요?
        -   피처 스케일링과 같은 전처리 단계를 올바르게 적용하는 파이프라인은 어떤 순서로 구성되어야 할까요? 왜 그 순서가 중요한가요?

2.  **99% 정확도의 함정: 불균형 데이터 문제**
    -   **상황**: 어떤 희귀병(전체 환자의 1%)을 예측하는 분류 모델을 만들었습니다. 테스트셋에서 99%의 정확도(Accuracy)를 달성했다고 팀에 보고하자, 한 선임 개발자가 결과에 우려를 표했습니다.
    -   **토론**:
        -   왜 99%의 정확도가 이 상황에서는 매우 나쁜 성능 지표일 수 있을까요? 만약 모델이 무조건 "정상"이라고만 예측한다면, 그 모델의 정확도는 몇 %가 될까요?
        -   이처럼 데이터 클래스가 심하게 불균형할 때, 정확도 대신 사용해야 할 더 나은 평가 지표는 무엇이 있을까요? 혼동 행렬(Confusion Matrix), 정밀도(Precision), 재현율(Recall), F1-점수(F1-score)는 각각 어떤 정보를 우리에게 알려주나요?

3.  **"완벽한" 테스트 점수에 대한 의심**
    -   **상황**: 타이타닉 생존자 예측 문제를 해결하기 위해 여러 모델과 특성을 조합해본 결과, 마침내 제공된 테스트셋에 대해 100%의 정확도를 달성했습니다.
    -   **토론**:
        -   이 결과를 기뻐해야 할까요, 아니면 의심해야 할까요? "완벽한" 점수가 나올 수 있는 잠재적인 원인들은 무엇일까요? (예: 데이터 누수, 너무 작거나 대표성이 없는 테스트셋, 특정 테스트셋에 대한 과적합 등)
        -   실제 서비스를 만든다고 가정할 때, 왜 최종 성능 검증을 위해 단 한 번만 사용하는 별도의 "검증(validation) 데이터셋"을 따로 떼어놓는 것이 중요한지 토론해보세요.

4.  **특성 중요도(Feature Importance)의 섣부른 해석**
    -   **상황**: 고객 이탈 예측을 위해 만든 랜덤 포레스트 모델이 '월 청구요금'을 가장 중요한 특성으로 지목했습니다. 이 결과를 보고, 마케팅팀은 모든 고객의 요금을 인하하는 캠페인을 기획하려 합니다.
    -   **토론**:
        -   이러한 의사 결정이 왜 섣부른 판단일 수 있을까요? 랜덤 포레스트는 특성 중요도를 어떤 방식으로 계산하나요?
        -   높은 특성 중요도가 '인과 관계'를 의미할까요, 아니면 단순한 '상관 관계'일 가능성이 높을까요? 이처럼 중요한 비즈니스 결정을 내리기 전에, 어떤 추가적인 분석이나 실험을 수행해야 할까요?


## 8. 되짚어보기 (Summary)

이번 주 우리는 데이터에서 패턴을 찾아 미래를 예측하는 머신러닝의 세계를 여행했습니다.

- **시각화는 눈**: Matplotlib와 Seaborn으로 데이터 속에 숨겨진 이야기를 보는 법을 배웠습니다.
- **머신러닝은 뇌**: Scikit-learn을 사용해 '훈련'과 '시험'이라는 과정을 거쳐 예측 모델을 만드는 법을 익혔습니다.
- **데이터는 생명**: "Garbage In, Garbage Out." 좋은 예측을 위해서는 결측치 처리, 피처 스케일링과 같은 데이터 전처리가 필수임을 이해했습니다.

이제 여러분은 데이터를 분석하고 예측 모델을 만들 수 있는 기본적인 역량을 갖추었습니다.

---
## 9. 트러블슈팅 (Troubleshooting)

- **그래프에 한글이 깨져서 `□□□` 형태로 나오나요?**
  - Matplotlib가 기본적으로 한글 폰트를 지원하지 않기 때문입니다. 아래 코드를 실행하여 시스템에 맞는 한글 폰트를 설정해주어야 합니다.

    ```python
    import matplotlib.pyplot as plt
    # For Windows
    # plt.rcParams['font.family'] = 'Malgun Gothic'
    # For macOS
    # plt.rcParams['font.family'] = 'AppleGothic'
    ```

- **`fit_transform()`은 훈련 데이터에만 사용하고, `transform()`은 테스트 데이터에 사용하라는 말이 무슨 뜻인가요?**
  - `fit()`은 데이터로부터 스케일링에 필요한 정보(e.g., 평균, 표준편차, 최소/최대값)를 '학습'하는 과정입니다. `transform()`은 학습된 정보를 바탕으로 데이터를 변환합니다. `fit_transform()`은 이 두 과정을 한 번에 수행합니다. 테스트 데이터는 '미래의 데이터'를 의미하므로, 훈련 데이터에서 학습한 '규칙'을 그대로 적용해야 합니다. 따라서 테스트 데이터에는 `fit()`을 다시 사용하지 않고, 훈련 데이터로 `fit()`한 스케일러를 사용하여 `transform()`만 적용해야 합니다.

- **모델의 성능이 너무 낮게 나오나요?**
  - 여러 가능성이 있습니다.
    - **데이터 전처리**: 결측치를 적절히 처리했나요? 범주형 변수(e.g., 'sex')를 숫자로 변환했나요? 피처 스케일링이 필요한 모델인데 적용했나요?
    - **특성 선택**: 모델에 너무 적은 특성을 사용했거나, 반대로 예측에 도움이 되지 않는 불필요한 특성을 너무 많이 사용했을 수 있습니다.
    - **모델 선택**: 현재 문제에 적합하지 않은 모델을 사용했을 수 있습니다. 'Model Selection Guide'를 참고하여 다른 모델을 시도해보세요.
    - **과적합/과소적합**: 훈련 데이터의 점수는 높은데 테스트 데이터의 점수가 현저히 낮다면 과적합(Overfitting)을, 둘 다 낮다면 과소적합(Underfitting)을 의심해볼 수 있습니다.

- **`ValueError: Input contains NaN, infinity or a value too large for dtype('float64').` 오류가 발생했나요?**
  - 모델의 입력 데이터(`X_train`)에 결측치(NaN), 무한대(infinity) 값이 포함되어 있다는 의미입니다. 모델을 학습시키기 전, `X_train.isnull().sum()` 과 같은 코드로 결측치를 확인하고, `fillna()` 등을 사용하여 적절히 처리해야 합니다.

더 자세한 문제 해결 가이드나 다른 동료들이 겪은 문제에 대한 해결책이 궁금하다면, 아래 문서를 참고해주세요.

- **➡️ [Geumdo-Docs: TROUBLESHOOTING.md](../../../TROUBLESHOOTING.md)**

---

## 10. 더 깊이 알아보기 (Further Reading)

### 실전 코드 & 튜토리얼
- [Scikit-learn 공식 예제 갤러리](https://scikit-learn.org/stable/auto_examples/index.html): 다양한 모델과 데이터셋에 대한 예제 코드의 보고
- [Seaborn 공식 튜토리얼](https://seaborn.pydata.org/tutorial.html): 더 아름답고 전문적인 시각화를 위한 가이드
- [Kaggle](https://www.kaggle.com/): 전 세계 데이터 과학자들이 모여 경쟁하는 플랫폼. 'Titanic'과 같은 다양한 입문용 프로젝트를 체험할 수 있습니다.

### 이론 및 개념 심화
- **[An Introduction to Statistical Learning (ISLR)](https://www.statlearning.com/)**: 머신러닝의 바이블로 불리는 명저. 통계적 이론 배경을 탄탄히 다지고 싶다면 필독을 권합니다. (PDF 무료 제공)
- **[StatQuest 유튜브 채널](https://www.youtube.com/c/statquest)**: 결정 트리, 로지스틱 회귀 등 머신러닝의 핵심 개념들을 가장 직관적이고 명쾌하게 설명해주는 채널입니다.
- **[Scikit-learn: 모델 평가 지표 가이드](https://scikit-learn.org/stable/modules/model_evaluation.html)**: 본문에서 다룬 정확도 외에 정밀도, 재현율, F1-score 등 다양한 평가 지표에 대한 상세한 설명과 사용법을 제공합니다.
- **[Seeing-Theory](https://seeing-theory.brown.edu/index.html)**: 확률 및 통계의 핵심 개념들을 인터랙티브 시각화 자료를 통해 체험하며 배울 수 있는 사이트입니다.

---

## 🚀 캡스톤 미니 프로젝트: 모델 성능 비교 및 파이프라인 구축

이번 장에서는 머신러닝의 전체 흐름을 배웠습니다. 하지만 실제 프로젝트에서는 단 하나의 모델만 만들어보는 경우는 거의 없습니다. 어떤 모델이 이 문제에 가장 적합한지, 그리고 데이터 전처리가 성능에 어떤 영향을 미치는지 체계적으로 '실험'하고 '비교'하는 과정이 필수적입니다.

이번 미니 프로젝트의 목표는 Scikit-learn의 `Pipeline`을 사용하여 데이터 전처리(스케일링)와 모델 훈련을 하나의 파이프라인으로 묶고, 여러 다른 모델의 성능을 체계적으로 비교하여 최적의 모델을 찾는 과정을 경험하는 것입니다.

### 프로젝트 목표

Scikit-learn의 내장 데이터셋인 붓꽃(Iris) 데이터를 사용하여, 다음 세 가지 모델의 성능을 '전처리 적용 전/후'로 나누어 비교하고, 그 결과를 보고서로 작성합니다.
1.  Logistic Regression
2.  Decision Tree Classifier
3.  Random Forest Classifier

**최종 분석 리포트 (예시):**
```
*** Model Performance Comparison Report ***

[Without Scaling]
- LogisticRegression Accuracy: 0.9333
- DecisionTreeClassifier Accuracy: 1.0000
- RandomForestClassifier Accuracy: 1.0000

[With StandardScaler]
- LogisticRegression Accuracy: 1.0000
- DecisionTreeClassifier Accuracy: 1.0000
- RandomForestClassifier Accuracy: 1.0000

[Analysis]
- 스케일링을 적용했을 때 Logistic Regression의 성능이 향상되었습니다.
- 트리 기반 모델인 Decision Tree와 Random Forest는 스케일링의 영향을 받지 않았습니다.
- ...
```

### 단계별 구현 가이드

**1. 데이터 준비**
- `sklearn.datasets`에서 `load_iris` 함수를 사용해 데이터를 불러오세요.
- `train_test_split`을 사용하여 데이터를 훈련셋과 테스트셋으로 분리합니다.

**2. 모델 비교 실험 (스케일링 미적용)**
- 비교할 모델들을 리스트에 담으세요: `[LogisticRegression(), DecisionTreeClassifier(), RandomForestClassifier()]`
- `for` 루프를 사용해 각 모델을 순회하며 다음을 반복합니다.
  - 모델을 훈련 데이터로 학습 (`fit`)
  - 테스트 데이터로 예측 (`predict`)
  - 정확도(`accuracy_score`)를 계산하고 결과를 저장

**3. Scikit-learn `Pipeline`으로 전처리 및 모델링 자동화**
- 데이터 전처리와 모델 학습을 하나의 객체로 묶어주는 `Pipeline`을 사용해 봅시다. 이는 데이터 누수(Data Leakage)를 방지하는 매우 중요한 실무 기법입니다.
- `from sklearn.pipeline import Pipeline`
- `from sklearn.preprocessing import StandardScaler`
- 다시 모델 리스트를 순회하며, 각 모델에 대해 `StandardScaler`와 모델을 포함하는 파이프라인을 생성합니다.
  - `pipe = Pipeline([('scaler', StandardScaler()), ('classifier', model)])`
- 전체 파이프라인을 훈련 데이터로 학습시키고(`pipe.fit`), 테스트 데이터로 정확도를 평가합니다.

**4. 결과 보고 및 분석**
- 위 두 실험(스케일링 전/후)의 결과를 보기 좋게 출력하세요.
- 결과에 대한 분석을 1~2줄로 덧붙여 보세요.
  - 왜 Logistic Regression 모델의 성능은 스케일링 후 변했는데, 트리 기반 모델들은 변하지 않았을까요? (힌트: 각 모델이 데이터를 어떻게 바라보는지 생각해보세요. 거리 기반 vs 규칙 기반)

**전체 코드 구조:**
```python
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.pipeline import Pipeline

# 1. 데이터 준비
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 2. 비교할 모델 리스트
models = [
    LogisticRegression(max_iter=1000),
    DecisionTreeClassifier(random_state=42),
    RandomForestClassifier(random_state=42)
]

# 3. 실험: 스케일링 전/후 성능 비교
results_no_scaling = {}
results_with_scaling = {}

print("--- Starting Model Evaluation ---")

for model in models:
    model_name = model.__class__.__name__
    
    # 스케일링 없이 학습 및 평가
    model.fit(X_train, y_train)
    pred_no_scaling = model.predict(X_test)
    results_no_scaling[model_name] = accuracy_score(y_test, pred_no_scaling)

    # 파이프라인으로 스케일링 적용 후 학습 및 평가
    pipe = Pipeline([
        ('scaler', StandardScaler()),
        ('classifier', model)
    ])
    pipe.fit(X_train, y_train)
    pred_with_scaling = pipe.predict(X_test)
    results_with_scaling[model_name] = accuracy_score(y_test, pred_with_scaling)

# 4. 결과 출력
print("\n*** Model Performance Comparison Report ***\n")
print("[Without Scaling]")
for model_name, acc in results_no_scaling.items():
    print(f"- {model_name} Accuracy: {acc:.4f}")

print("\n[With StandardScaler]")
for model_name, acc in results_with_scaling.items():
    print(f"- {model_name} Accuracy: {acc:.4f}")

print("\n[Analysis]")
print("로지스틱 회귀와 같은 거리 기반 알고리즘은 피처 스케일링에 영향을 받지만,")
print("결정 트리 기반 알고리즘은 각 피처를 독립적으로 보기 때문에 스케일링의 영향을 거의 받지 않습니다.")
print("---------------------------------------")
```
이러한 체계적인 실험 과정을 통해, 여러분은 단순히 하나의 모델을 만드는 것을 넘어, 주어진 문제와 데이터에 가장 적합한 해결책을 '찾아내는' 데이터 과학자의 역량을 기르게 될 것입니다.

---

**➡️ 다음 시간: [Part 7: 딥러닝 기초와 PyTorch](../07_deep_learning/part_7_deep_learning.md)**
