모의고사는 100점, 실전은 50점
과적합(Overfitting)은 “너무 잘 맞춘다(Fit too much)”는 뜻 그대로, 모델이 훈련 데이터의 진짜 패턴뿐 아니라 노이즈나 그 데이터에만 있는 우연한 특징까지 외워버린 상태다. 모의고사 문제를 통째로 외워 100점을 받았지만, 문제가 바뀐 실전 수능에서는 50점을 받는 것과 같다.
구분 | 정상적인 학습 | Overfitting |
|---|---|---|
학습 대상 | 데이터의 본질적 패턴 | 데이터의 노이즈나 특수 상황까지 반영 |
모델 복잡도 | 적절 — 규칙적인 구조 | 과도 — 지나치게 복잡 |
검증 성능 | 훈련·검증 성능이 안정적으로 유지됨 | 훈련 성능만 높고 검증 성능은 낮거나 불안정함 |
머신러닝 알고리즘은 기본적으로 훈련 데이터에 대한 성능을 계속 끌어올리는 방향으로 학습하기 때문에, 과적합은 예외적인 사고가 아니라 항상 관리해야 하는 기본 위험이다. 나무가 깊어질수록, 파라미터가 많아질수록, 학습 데이터가 적고 노이즈가 많을수록 더 쉽게 발생한다.
Train·Validation·Test, 왜 세 조각으로 나누나
과적합 여부는 훈련에 쓰지 않은 데이터로 성능을 확인해야 알 수 있다. 그래서 데이터를 보통 세 조각으로 나눈다.
조각 | 역할 | 손대는 시점 |
|---|---|---|
Train (훈련) | 모델이 파라미터를 학습하는 데 쓰는 데이터 | 학습 과정 내내 |
Validation (검증) | 하이퍼파라미터 튜닝·모델 선택에 쓰는 데이터 | 학습 중 반복적으로 확인 |
Test (평가) | 최종 모델의 일반화 성능을 딱 한 번 확인하는 데이터 | 모든 튜닝이 끝난 뒤 마지막에 한 번 |
핵심은 Test 데이터를 튜닝 과정에 절대 섞지 않는 것이다. Test 성능을 보고 다시 하이퍼파라미터를 고치기 시작하면, Test는 더 이상 “한 번도 보지 못한 데이터”가 아니게 되고 이를 데이터 누수(Data Leakage)라고 부른다. 세 조각 각각에서 R²·RMSE·Accuracy 같은 지표를 구해 비교하는 방식을 Single-Split Evaluation이라고 한다.
코드로 과적합 직접 확인하기
노이즈가 섞인 분류 데이터를 만들고, 나무 깊이를 다르게 해서 Train·Validation·Test 정확도를 비교해본다.
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
X, y = make_classification(
n_samples=150, n_features=20, n_informative=3, n_redundant=2,
flip_y=0.15, random_state=42,
)
X_train, X_temp, y_train, y_temp = train_test_split(
X, y, test_size=0.4, random_state=42
)
X_valid, X_test, y_valid, y_test = train_test_split(
X_temp, y_temp, test_size=0.5, random_state=42
)
for depth in [3, None]:
model = DecisionTreeClassifier(max_depth=depth, random_state=42).fit(X_train, y_train)
train_acc = accuracy_score(y_train, model.predict(X_train))
valid_acc = accuracy_score(y_valid, model.predict(X_valid))
test_acc = accuracy_score(y_test, model.predict(X_test))
print(f"max_depth={depth}: train={train_acc:.3f}, valid={valid_acc:.3f}, test={test_acc:.3f}")
max_depth=3: train=0.967, valid=0.767, test=0.833
max_depth=None: train=1.000, valid=0.733, test=0.800
깊이 제한이 없는 나무( max_depth=None)는 훈련 정확도가 100%까지 올라갔지만, 검증·평가 정확도는 오히려 깊이 3인 나무보다 낮다. 훈련 점수만 보고 “깊을수록 좋다”고 판단했다면 놓쳤을 신호를, Validation·Test 비교가 잡아낸 것이다.
과적합을 줄이는 방법
모델 복잡도 제한 — 나무 최대 깊이 제한, 정규화(LASSO·Ridge) 패널티 강화 등.
데이터 늘리기 — 가능하다면 학습 데이터를 더 확보하거나 데이터 증강을 활용한다.
교차검증(Cross-Validation) — 데이터를 한 번만 나누지 않고 여러 번 나눠 평균 성능을 본다.
조기 종료(Early Stopping) — 검증 성능이 더 이상 좋아지지 않는 시점에 학습을 멈춘다(부스팅·신경망에서 자주 사용).
정리
과적합은 모델이 데이터를 “이해”하지 않고 “암기”했을 때 생긴다. 훈련 성능만으로는 이를 알아챌 수 없기 때문에 Train·Validation·Test로 데이터를 나눠 한 번도 보지 않은 데이터에서의 성능을 반드시 함께 확인해야 한다. Test 데이터는 모든 튜닝이 끝난 뒤 마지막에 딱 한 번만 확인하는 것이 데이터 누수를 막는 핵심 규칙이다.
참고 자료
Overfitting — Wikipedia — 과적합의 일반적 정의와 배경 (2026-08-07 확인)
train_test_split — scikit-learn 공식 문서 — 데이터 분할 함수의 파라미터와 사용법 (2026-08-07 확인)
댓글 0
댓글을 불러오는 중…