[머신러닝 중급 1편] 과적합과 과소적합 — 모델이 시험 문제만 외우면 생기는 일
처음 머신러닝을 배울 때 '과적합'이 뭔 소린지 감이 안 왔습니다. 잘 맞추면 좋은 거 아닌가? 근데, 직접 코드를 돌려보고 나서야 이해했던 경험이 있습니다. degree 하나 바꿨을 뿐인데 그래프가 미친 듯이 요동치는 걸 보고.. 과적합·과소적합의 차이, 편향-분산 트레이드오프, 학습 곡선까지 직접 실행하면서 정리합니다.
시작하며 — 시험 공부의 딜레마
솔직히 말하면, 처음 머신러닝을 배울 때 과적합이라는 단어가 와닿지 않았습니다.
"훈련 데이터에 너무 맞춰졌다"는 게 대체 무슨 뜻이지? 잘 맞추면 좋은 거 아닌가?
그러다 직접 모델을 돌려보고 나서야 이해했습니다.ㅋㅋ..
학교 다닐 때, 기출문제만 달달 외워서 모의고사 100점 맞는 친구 있었잖아요.
근데 실전 수능에서는 망하는 그 케이스.
문제를 외운 거지, 풀이법을 배운 게 아니었기 때문입니다.
머신러닝 모델도 똑같은 실수를 합니다.
훈련 데이터에 너무 딱 맞춰진 모델 — 이걸 과적합(Overfitting)이라고 해요.
이번 편에서는 제가 직접 코드를 돌려보면서 "아, 이게 과적합이구나" 느꼈던 과정을 같이 공유합니다.
과소적합 vs 적정 vs 과적합 — 한눈에 비교
다항 회귀(Polynomial Regression)로 세 가지 모델을 비교해봤습니다.
degree(차수) 값 하나 바꿨을 뿐인데, 모델 성격이 완전히 달라지더라고요.
degree=1 (과소적합) — 직선 하나로 전체를 설명. 너무 단순해서 패턴을 못 잡음
degree=5 (적정) — 데이터의 실제 패턴을 잘 따라감
degree=15 (과적합) — 노이즈까지 전부 외워서 구불구불. 새 데이터에서 망함
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
import numpy as np
# 각 degree별 모델 학습
for degree in [1, 5, 15]:
model = Pipeline([
('poly', PolynomialFeatures(degree=degree)),
('linear', LinearRegression())
])
model.fit(X_train, y_train)
train_score = model.score(X_train, y_train)
test_score = model.score(X_test, y_test)
print(f"degree={degree:2d} | train={train_score:.3f} | test={test_score:.3f}")
직접 주피터에서 돌려봤습니다. degree=1은 뭐.. 직선이라 패턴을 아예 못 잡고,
degree=15는 보자마자 "아 이건 아닌데" 싶었어요. 곡선이 미친 듯이 요동칩니다.
왼쪽(degree=1)은 너무 심플해서 데이터 패턴을 놓치고,
오른쪽(degree=15)은 모든 점을 지나려고 난리를 치고 있죠.
가운데(degree=5)가 그나마 자연스럽게 흐름을 따라가는 적정 수준입니다.
처음 이 그래프를 봤을 때 과적합이 뭔지 바로 체감됐어요.
편향-분산 트레이드오프
위에서 과소적합과 과적합을 봤는데, 사실 이 둘은 동전의 양면입니다.
한쪽을 줄이면 다른 쪽이 올라가는 구조예요. 처음엔 "그냥 둘 다 줄이면 되는 거 아닌가?" 싶었는데,
공부할수록 그게 안 된다는 걸 깨달았습니다. 이걸 편향-분산 트레이드오프라고 합니다.
편향(Bias) — 모델이 얼마나 잘못된 가정을 하는가. 높으면 과소적합
분산(Variance) — 데이터가 조금 바뀌어도 예측이 크게 흔들리는가. 높으면 과적합
Total Error = Bias² + Variance + Irreducible Noise
모델을 복잡하게 만들면 편향은 낮아지지만 분산이 높아집니다.
반대로 단순하게 만들면 분산은 낮아지지만 편향이 높아집니다.
최적 지점을 찾는 것이 머신러닝의 핵심 과제입니다.
학습 곡선 — 과적합을 시각적으로 진단한다
학습 곡선(Learning Curve)은 훈련 데이터 크기에 따른 train/validation 점수 변화를 보여줍니다.
두 곡선의 관계로 현재 상태를 진단할 수 있습니다.
두 곡선이 수렴 → 적정 (Good Fit)
두 곡선 모두 낮음 → 과소적합 (Underfitting)
두 곡선이 벌어짐 → 과적합 (Overfitting)
여기서 헷갈리기 쉬운 포인트가 하나 있습니다.
그래프 왼쪽(데이터가 적을 때)에도 두 곡선이 벌어져 있거든요. 근데 이건 과적합이 아닙니다.
학습 데이터가 적으면 train은 당연히 높고 val은 낮아요. 데이터가 늘면서 좁혀지는 건 정상적인 흐름입니다.
진짜 과적합 신호는 "좁혀지다가 다시 벌어지는" 구간입니다.
데이터를 더 줘도 갭이 안 줄거나, 오히려 다시 커지기 시작하면 — 그게 과적합이 시작된 지점이에요.
위 그래프에서 빨간 영역이 바로 그 구간입니다.
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
import numpy as np
train_sizes, train_scores, val_scores = learning_curve(
model, X, y,
train_sizes=np.linspace(0.1, 1.0, 7),
cv=5,
scoring='accuracy'
)
train_mean = train_scores.mean(axis=1)
val_mean = val_scores.mean(axis=1)
plt.plot(train_sizes, train_mean, label='Train score', color='#4FD1C5')
plt.plot(train_sizes, val_mean, label='Validation score', color='#E6BE50')
plt.xlabel('Training set size')
plt.ylabel('Score')
plt.legend()
plt.show()
직접 돌려보니까 이런 결과가 나왔습니다. 처음에는 "이게 뭐지?" 싶었는데, 잘 보면 재밌어요.
데이터가 적을 때는 Train error와 Validation error 차이가 확 벌어집니다.
데이터가 늘어나면서 두 곡선이 점점 가까워지는 게 보이죠?
이게 안 좁혀지고 계속 벌어져 있으면 — 과적합 신호입니다.
저도 처음엔 그래프만 봐서는 감이 안 왔는데, 직접 degree를 바꿔가면서 학습 곡선을 여러 번 그려보니까 확실히 느껴지더라고요.
과적합 해결 방법 4가지
과적합을 잡는 방법은 여러 가지가 있는데, 실제로 써보니 상황에 따라 효과가 다릅니다.
제가 정리한 4가지 방법입니다.
1. 더 많은 데이터
가장 확실한 해결책입니다. 데이터가 다양할수록 모델이 패턴을 제대로 배울 확률이 올라가요.
현실에서는 데이터를 무한정 구할 수 없으니 데이터 증강(Augmentation)으로 보완하는 경우가 많습니다.
2. 정규화 (Regularization)
가중치에 패널티를 부여해서 모델이 너무 복잡해지지 않도록 막는 방법입니다.
L1(Lasso)은 불필요한 특성을 아예 제거하고, L2(Ridge)는 가중치를 전체적으로 줄여요.
이 부분은 내용이 많아서 다음 편(3편)에서 따로 정리할 예정입니다.
3. 모델 단순화
결정 트리 깊이를 제한하거나, 특성 수를 줄이거나, 뉴럴넷 레이어를 줄이는 방법입니다.
max_depth, max_features 같은 파라미터를 조절하면 됩니다.
위에서 degree=15를 5로 낮춘 것도 결국 모델 단순화의 한 예시입니다.
4. 교차 검증 (Cross-Validation)
데이터를 여러 묶음으로 나눠서 돌아가며 학습/검증을 반복하는 방법입니다.
한 번의 train/test 분리보다 훨씬 안정적인 성능 측정이 가능합니다.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
print(f"CV scores: {scores}")
print(f"Mean: {scores.mean():.3f} ± {scores.std():.3f}")
정리
처음에 과적합이라는 개념이 추상적으로 느껴졌는데,
직접 degree를 바꿔가면서 그래프를 그려보니까 바로 이해가 됐습니다.
역시 머신러닝은 직접 돌려봐야 감이 와요.
1. 과적합 — 훈련 데이터에 너무 맞춰져서 새 데이터에서 실패한다
2. 학습 곡선 — train/validation 점수 차이로 지금 모델 상태를 진단할 수 있다
3. 해결책 — 데이터 늘리기 / 정규화 / 모델 단순화 / 교차검증
다음 편(2편)에서는 서포트 벡터 머신(SVM)을 다룹니다.
두 그룹 사이의 가장 넓은 길을 찾는 알고리즘인데, 마진 최대화와 커널 트릭 개념이 생각보다 직관적이에요.
다음 편에서 같이 정리해보겠습니다.
