학습 데이터 점수가 좋다고 좋은 모델이 아니에요. 안 본 데이터(시험)에서 잘해야 진짜 — 기계학습 평가의 핵심을 다항 회귀로 직접 확인해 봐요.
파란 원은 모델이 공부한 학습 데이터(14개), 주황 삼각형은 숨겨둔 시험 데이터(6개)예요. 모델(보라 곡선)은 파란 원만 보고 학습해요. 보라 곡선이 회색 점선(진짜 규칙)과 비슷하면 이해한 것, 파란 원 사이사이를 억지로 다 지나가며 출렁이면 외운 거예요.
가로축은 차수(1~12), 세로축은 오차(MSE)예요. 학습 오차(파랑)는 차수를 올릴수록 계속 내려가지만, 시험 오차(주황)는 내려가다 다시 솟는 U자를 그려요. 두 곡선이 갈라지는 지점부터가 과적합이에요. 폭발한 시험 오차는 위쪽 상한에서 잘라 그렸어요.
학습 오차가 아무리 작아도 시험 오차가 커지면 과적합이에요. 시험 오차가 가장 작은 차수가 이 데이터에 딱 맞는 복잡도입니다.
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# 데이터를 학습용/시험용으로 나눠요 — 시험 문제는 숨겨둡니다!
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3)
for d in range(1, 13): # 차수 1~12를 전부 시험
poly = PolynomialFeatures(degree=d) # x → [1, x, x², ..., x^d]
model = LinearRegression().fit(poly.fit_transform(X_tr), y_tr)
err_tr = mean_squared_error(y_tr, model.predict(poly.transform(X_tr)))
err_te = mean_squared_error(y_te, model.predict(poly.transform(X_te)))
print(f"차수 {d:2d} | 학습 오차 {err_tr:.2f} | 시험 오차 {err_te:.2f}")
# 학습 오차는 계속 줄지만 시험 오차는 U자로 다시 커져요 — 과적합!