1장. 머신러닝 프로세스와 기본 개념
실습 6 — 기준값 바꾸고 과적합 확인하기
실습 5의 모델로 기준값을 바꿔 가며 재현율과 정밀도가 어떻게 움직이는지 보고, 의사결정나무의 깊이를 바꿔 과적합을 직접 확인합니다.
1단계. 준비하고 모델 학습하기
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
# 실습 4, 5와 똑같이 준비하고 같은 모델을 학습한다
df = pd.read_csv("out_delivery_clean.csv")
df["주말"] = (pd.to_datetime(df["주문일"]).dt.day_of_week >= 5).astype(int)
features = ["주문시각", "거리km", "무게kg", "주말", "지역", "상품분류", "날씨", "택배사"]
X = pd.get_dummies(df[features], dtype=int)
y = df["지연"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
model = LogisticRegression(max_iter=1000).fit(X_train, y_train)
print("시험용 정확도:", round(model.score(X_test, y_test), 3))시험용 정확도: 0.7992단계. 기준값 바꿔 보기
from sklearn.metrics import precision_score, recall_score
# predict_proba 는 [정시일 확률, 지연일 확률] 두 열을 돌려준다
# [:, 1] 은 둘째 열, 곧 지연일 확률만 뽑는다
proba = model.predict_proba(X_test)[:, 1]
for t in [0.5, 0.4, 0.3, 0.2]:
# 지연 확률이 기준값 t 이상이면 1(지연)
p = (proba >= t).astype(int)
print(f"기준값 {t}: 정밀도 {precision_score(y_test, p):.3f} "
f"재현율 {recall_score(y_test, p):.3f} 지연으로 본 주문 {p.sum()}건")기준값 0.5: 정밀도 0.536 재현율 0.242 지연으로 본 주문 28건
기준값 0.4: 정밀도 0.532 재현율 0.403 지연으로 본 주문 47건
기준값 0.3: 정밀도 0.453 재현율 0.468 지연으로 본 주문 64건
기준값 0.2: 정밀도 0.321 재현율 0.581 지연으로 본 주문 112건3단계. 나무의 깊이와 과적합
from sklearn.tree import DecisionTreeClassifier
# 같은 데이터로 모델만 의사결정나무로 바꿔 끼운다(만들기 → fit → score 는 그대로)
# max_depth: 질문을 몇 번까지 이어 갈지. None 은 제한 없음
for depth in [2, 4, 8, None]:
tree = DecisionTreeClassifier(max_depth=depth, random_state=42).fit(X_train, y_train)
# 학습용 점수와 시험용 점수를 나란히 찍어 벌어지는지 본다
print(f"깊이 {depth}: 학습 {tree.score(X_train, y_train):.3f} 시험 {tree.score(X_test, y_test):.3f}")깊이 2: 학습 0.820 시험 0.803
깊이 4: 학습 0.845 시험 0.806
깊이 8: 학습 0.913 시험 0.769
깊이 None: 학습 1.000 시험 0.732이 실습이 뜻하는 것
이 실습은 두 가지 손잡이를 돌려 보는 일입니다. 먼저 실습 5와 같은 모델을 다시 만들고(1단계), 화재경보기의 민감도 손잡이를 돌리듯 "몇 % 이상이면 지연이라고 할까"를 바꿔 보고(2단계), 마지막으로 학생이 문제집을 얼마나 깊이 외우게 할지 정하듯 의사결정나무가 질문을 몇 번까지 이어 갈지 바꿔 봅니다(3단계). 여기서 민감도 손잡이가 기준값, 외우는 정도가 max_depth, 문제집을 통째로 외워 새 문제에 약해지는 것이 과적합입니다.
| 단계 | 출력 | 뜻 |
|---|---|---|
| 1. 준비 | 시험용 정확도 0.799 | 실습 5와 같은 모델이 만들어졌습니다 |
| 2. 기준값 0.5 | 정밀도 0.536, 재현율 0.242, 28건 | 예민하지 않은 경보기입니다. 28건만 "지연"이라고 해서 놓치는 주문이 많습니다 |
| 2. 기준값 0.3 | 정밀도 0.453, 재현율 0.468, 64건 | 손잡이를 돌리자 실제 지연을 절반 가까이 잡았지만, 맞는 경보의 비율은 줄었습니다 |
| 2. 기준값 0.2 | 정밀도 0.321, 재현율 0.581, 112건 | 112건을 "지연"이라고 해서 실제 지연 62건 가운데 36건쯤을 잡았지만, 나머지 76건쯤은 헛경보입니다 |
| 3. 깊이 4 | 학습 0.845, 시험 0.806 | 시험 점수가 가장 높은 깊이입니다 |
| 3. 깊이 None | 학습 1.000, 시험 0.732 | 공부한 문제는 다 맞히지만 새 문제는 오히려 더 틀립니다. 외워 버린 상태, 곧 과적합입니다 |
한 줄로 줄이면, 기준값은 "놓침"과 "헛경보"를 맞바꾸는 손잡이이고, 나무를 너무 깊게 키우면 학습용만 외운다는 것을 숫자로 확인한 실습입니다. 어느 기준값이 좋은지는 숫자가 정해 주지 않고, 놓침과 헛경보 가운데 무엇이 더 아픈지라는 업무 판단으로 정합니다. 여기서는 시험용으로 견주었지만, 실제로 고를 때는 검증용 데이터를 따로 씁니다.
코드 설명
- 기준값을 0.3 으로 낮추면 재현율은 0.242 에서 0.468 로 오르고, 정밀도는 0.536 에서 0.453 으로 내려갑니다. 0.2 까지 낮추면 지연으로 보는 주문이 112건으로 늘어 헛경보가 많아집니다. "기준값 바꾸기" 절의 그림대로 움직입니다.
- 0.5 에서 0.4 로 갈 때는 정밀도가 0.536 에서 0.532 로 거의 그대로입니다. 늘 똑같이 내려가지는 않고 "대체로" 내려갑니다.
- 깊이 4 에서 시험 점수가 0.806 으로 가장 높고, 깊이 제한이 없으면 학습 1.000, 시험 0.732 로 크게 벌어집니다. "과적합" 절 그림의 "외워 버림" 구간입니다.
- 여기서는 과적합을 보이려고 시험용 점수로 깊이를 견주었습니다. 실제로 깊이와 기준값을 고를 때는 검증용 데이터를 따로 씁니다.