๊ฒ์ฆ์ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ํ๊ฐํ ์ ์๋ ๋ฐฉ๋ฒ์ด๋ค. ๊ฒ์ฆ์๋ ํฌ๊ฒ Hold-out Validation, K-Fold Cross Validation, LOOCV (Leave-One-Out Cross Validation)์ด ์๋ค.
ํ๋์์ ๊ฒ์ฆ ๋ฐฉ์์ ์ง๊ธ๊น์ง ํด์๋ ๋ฐฉ์๊ณผ ๋น์ทํ๋ค. ์ฆ, ์ ์ฒด ๋ฐ์ดํฐ ์
์ training set๊ณผ test set์ผ๋ก ์ผ์ ๋น์จ์ ํตํด ๋๋์ด์ ์งํํ๋ ๊ฒ์ด ํ๋์์ ๊ฒ์ฆ ๋ฐฉ์์ด๋ค. (์ฐธ๊ณ ๋ก ํ์ดํผํ๋ผ๋ฏธํฐ ํ๋์ด ํ์ํ ๊ฒฝ์ฐ, ํน์ ๋ฅ๋ฌ๋ ๊ฐ์ ๊ฒฝ์ฐ์๋ Train set / Validation set / Test set ์ผ๋ก ๋๋์ด ์ฌ์ฉํ ์๋ ์๋ค.)
์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ด ํ๋์์ ๊ฒ์ฆ์ ์จ์๋ค.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
ํ๋์์ ๊ฒ์ฆ ๋ฐฉ์์ ๋ฐ์ดํฐ๊ฐ ๋ง๊ณ ๋น ๋ฅด๊ณ ๊ฐ๋จํ๊ฒ ๋ชจ๋ธ ์ฑ๋ฅ์ ํ๊ฐํ๊ณ ์ถ์ ๋ ํจ๊ณผ์ ์ด๋ค.
ํ์ง๋ง ๋ฐ์ดํฐ๊ฐ ๋ถ์กฑํ ๊ฒฝ์ฐ, ํ๋ จ ๋ฐ์ดํฐ์ ํ ์คํธ ๋ฐ์ดํฐ์ ๋ถํ ์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ํฌ๊ฒ ๋ฌ๋ผ์ง ์ ์๊ณ , ํ ์คํธ ๋ฐ์ดํฐ๋ ํ๋ จ์ ์ฌ์ฉ๋์ง ์๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ์ ํ์ฉ ์ธก๋ฉด์์ ๊ต์ฅํ ๋นํจ์จ์ ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ๋ง ๋๋๊ธฐ ๋๋ฌธ์ ์ผ๋ฐํ ์ฑ๋ฅ์ ์ ๋๋ก ํ๊ฐํ๊ธฐ ์ด๋ ค์ธ ์ ์๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๊ต์ฐจ ๊ฒ์ฆ (Cross Validation)์ ์ด์ฉํ๋ ๊ฒ์ด ์ข๋ค. ๊ต์ฐจ ๊ฒ์ฆ ์ค k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ๋ํด์ ๋จผ์ ์์๋ณด์.
k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ํ ๋๋ ๋จผ์ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ k ๊ฐ์ ๊ฐ์ ์ฌ์ด์ฆ๋ก ๋๋๋ค. ์๋ฅผ ๋ค์ด k=5, ๋ฐ์ดํฐ๊ฐ ์ด 1000๊ฐ๊ฐ ์๋ค๋ฉด ์ด ๋ฐ์ดํฐ๋ฅผ 200๊ฐ์ฉ 5๊ฐ์ ์
์ผ๋ก ๋๋๋ฉด ๋๋ค.

์ด ๋ฐ์ดํฐ ์ ๋ค์ ์ด์ฉํด์ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ฌ๋ฌ ๋ฒ ๊ฒ์ฆํ ๊ฑด๋ฐ, ๋งจ ์ฒ์์๋ ๊ฐ์ฅ ์์/์์ ์๋ ๋ฐ์ดํฐ ์ ์ test test์ผ๋ก ์ฌ์ฉํ๊ณ , ๋๋จธ์ง๋ฅผ training set์ผ๋ก ์ฌ์ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ ๊ฒ ํ์ ๋์ ์ฑ๋ฅ์ ์ฒดํฌํ๋ค.

๊ทธ ๋ค์์๋ ๋ ๋ฒ์งธ ๋ฐ์ดํฐ ์ ์ test set์ผ๋ก ์ฌ์ฉํ๊ณ , ๋๋จธ์ง 4๊ฐ๋ฅผ training set์ผ๋ก ์ฌ์ฉํด์ ๋ค์ ๋ชจ๋ธ์ ํ์ต์ํจ๋ค. ๊ทธ๋ฆฌ๊ณ ๋๋ค์ ์ด ๋์ ์ฑ๋ฅ์ ํ์ ํ๋ค. ์์๋ ์์ ๊ฐ๋ค.

์ด ๊ณผ์ ์ ๋ชจ๋ ๋ฐ์ดํฐ ์ ์ ๋ฐ๋ณตํด์ค๋ค. ๊ทธ๋ฌ๋ฉด ์์ ๊ฐ์ด 5๊ฐ์ ํ ์คํธ ์ ์ ๋ํ ์ฑ๋ฅ์ด k๊ฐ ์ฆ, 5๊ฐ ์์ ํ ๋ฐ, ์ด ์ฑ๋ฅ 5๊ฐ์ ํ๊ท ์ ๋ชจ๋ธ ์ฑ๋ฅ์ผ๋ก ๋ณด๋ ๊ฒ์ด๋ค. ๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ฌ๋ฌ ๋ฒ ๋ค๋ฅธ ๋ฐ์ดํฐ๋ก ๊ฒ์ฆ(๊ต์ฐจ ๊ฒ์ฆ)ํ๊ธฐ ๋๋ฌธ์ ํ๊ฐ์ ๋ํ ์ ๋ขฐ๊ฐ ์ฌ๋ผ๊ฐ ์ ์๋ค.
k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ์ง์ ์ค์ต ํด๋ณด์.
from sklearn import datasets
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
import numpy as np
import pandas as pd
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning) # ๊ฒฝ๊ณ ๋ฉ์ธ์ง ๋ฌด์ํ๋ ์ฉ๋
iris_data = datasets.load_iris()
X = pd.DataFrame(iris_data.data, columns=iris_data.feature_names)
y = pd.DataFrame(iris_data.target, columns=['Class'])
logistic_model = LogisticRegression(max_iter=2000)
cross_val_score(logistic_model, X, y.values.ravel(), cv=5) # k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ํ ๋ชจ๋ธ, ์
๋ ฅ ๋ณ์, ๋ชฉํ ๋ณ์, k๋ฅผ ์ ํ๋ ํ๋ผ๋ฏธํฐ
์ด๋ ๊ฒ 5๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ์งํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ 5๊ฐ์ ์ฑ๋ฅ์ด ๋ํ์ด ๋ฐฐ์ด๋ก ์ถ๋ ฅ๋๋ค.
array([0.96666667, 1. , 0.93333333, 0.96666667, 1. ])
์ด ์ฑ๋ฅ๋ค์ ํ๊ท ์ ๋ด๋ฉด ์ผ๋ฐํ๋ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ ์ ์๋ ๊ฒ์ด๋ค.
np.average(cross_val_score(logistic_model, X, y.values.ravel(), cv=5)) # 5๊ฐ์ ์ฑ๋ฅ์ ํ๊ท ์ ๋ธ๋ค
๊ฒฐ๊ณผ: 0.9733333333333334
k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์๋ ๋จ์ ์ด ์๋ค. ๋ฐ๋ก ๋ฐ์ดํฐ ํธํฅ์ด ์กด์ฌํ๋ ๊ฒฝ์ฐ, ์ ๋๋ก ๋ ๋ชจ๋ธ ํ์ต๊ณผ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ง์ง ์์ ์ ์๋ค.
์๋ฅผ ๋ค์ด ํด๋์ค 0์ด 95%, ํด๋์ค 1์ด 5%์ธ ๋ฐ์ดํฐ์ ์ด ์๋ค๊ณ ๊ฐ์ ํ์. ์ผ๋ฐ K-Fold๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ๋ถ ํด๋์์๋ ํด๋์ค 1์ด ๊ฑฐ์ ํฌํจ๋์ง ์์ ์ ์๋ค. ์ ๋ง ๊ทน๋จ์ ์ผ๋ก๋ ์ผ๋ถ ํด๋์๋ ํด๋์ค 0๋ง ๊ฐ๋์ฐจ ์์ ์ ์๋ ๊ฒ์ด๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ณ์ธต์ K-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ํ๋ค.
๊ณ์ธต์ K-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ๋ชจ๋ ํด๋์์ ํด๋์ค์ ๋น์จ๋ค์ ๋์ผํ๊ฒ ๋ง๋ ๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ฐ์ดํฐ๊ฐ ํธํฅ๋์ด ์์ ๊ฒฝ์ฐ k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ํ์ ๋๋ณด๋ค ๋ ์์ ์ ์ธ ๋ชจ๋ธ ํ๊ฐ๊ฐ ๊ฐ๋ฅํด์ง๋ค.
์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
from sklearn.model_selection import StratifiedKFold, cross_val_score
# Stratified K-Fold ์ค์ (K=5)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# ๋ก์ง์คํฑ ํ๊ท ๋ชจ๋ธ ํ์ต ๋ฐ ํ๊ฐ
logistic_model = LogisticRegression(max_iter=200)
# ๊ต์ฐจ ๊ฒ์ฆ ์ํ
scores = cross_val_score(logistic_model, X, y, cv=skf)
๊ณ์ธต์ k-๊ฒน ๊ต์ฐจ๊ฒ์ฆ์ ๋ฐ์ดํฐ๊ฐ ์ด๋ฏธ ๊ท ํ๋์ด ์๋ค๋ฉด ๊ทธ๋ฅ ์ผ๋ฐ k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ์ฌ์ฉํด๋ ์ข๋ค.
ํ์ง๋ง ๋ฐ์ดํฐ๊ฐ ๋๋ฌด ์ ์ด์ ํน์ ํด๋์ค๊ฐ ํน์ ํด๋์ ๊ฑฐ์ ํฌํจ๋์ง ์๋ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ณ ์ถ์ ๋์ ๊ณ์ธต์ k-๊ฒน ๊ต์ฐจ๊ฒ์ฆ์ ์ฌ์ฉํ๋ฉด ํจ๊ณผ์ ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ๊ณ์ธต์ k-๊ฒน ๊ต์ฐจ๊ฒ์ฆ์ ๋ถ๋ฅ ๋ฌธ์ ์์๋ง ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํ๊ท์์๋ ์ฌ์ฉํ์ง ์์๋ ๋๋ค.
LOOCV๋ K-Fold ๊ต์ฐจ ๊ฒ์ฆ์ ๊ทน๋จ์ ์ธ ๊ฒฝ์ฐ๋ก, k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์์๋ ์ํ๋ง๋ ๋ฐ์ดํฐ๊ฐ ํด๋(๊ตฐ์ง)์ด์ง๋ง LOOCV์์๋ ๋ฑ๊ฐ์ด๋ค.
๋ค์ ๋งํด LOOCV๋ ๋ฐ์ดํฐ๋ฅผ ๋ฑ๊ฐ๋ก ๋ฝ์ K-Fold ๊ต์ฐจ ๊ฒ์ฆ ๋ฐฉ์์ผ๋ก ์งํํ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ๋ฐ์ดํฐ๊ฐ N๊ฐ ์์ผ๋ฉด, N-Fold ๊ต์ฐจ ๊ฒ์ฆ์ ์ํํ๋ ๊ฒ๊ณผ ๋์ผํ๋ค๊ณ ๋ณผ ์ ์๋ค.
์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
from sklearn.model_selection import LeaveOneOut, cross_val_score
# LOOCV ์ค์
loo = LeaveOneOut()
# ๋ก์ง์คํฑ ํ๊ท ๋ชจ๋ธ
logistic_model = LogisticRegression(max_iter=200)
# LOOCV ์ํ
scores = cross_val_score(logistic_model, X, y, cv=loo)
LOOCV๋ ๋ฐ์ดํฐ๋ฅผ ๋ฑ๊ฐ๋ก ์ํ๋ง ํ๊ธฐ ๋๋ฌธ์ ์ฐ์ฐ ๋น์ฉ์ด ๊ต์ฅํ ํฌ๋ค. ๋ฐ๋ผ์ LOOCV๋ ๋ฐ์ดํฐ๊ฐ ๋งค์ฐ ์ ์ง๋ง k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ ๋ฐฉ์์ ์ฑํํ๊ณ ์ถ์ ๋ ํจ๊ณผ์ ์ด๋ค.
๊ทธ๋ฆฌ๋ ์์น๋ ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ํ๋ํ๋ ๋ฐฉ๋ฒ ์ค ํ๋์ด๋ค.
๋จผ์ ํ์ดํผ ํ๋ผ๋ฏธํฐ์ ๋ํด ์์๋ณด์.
Lasso ๋ชจ๋ธ์ ์์๋ก ๋ณด์.
scikit-learn์์ Lasso ๋ชจ๋ธ์ ๋ง๋ค ๋ alpha์ max_iter๋ผ๋ ์ต์
๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ง์ ํด์คฌ๋ค.
model = Lasso(alpha=0.001, max_iter=1000)
๋ณต์ตํ๋ฉด alpha ๋ ์ ๊ทํญ์ ๊ณฑํด์ง๋ ์์ ์๊ณ , max_iter ๋ ๊ฒฝ์ฌ ํ๊ฐ์ ์ต๋ํ ๋ช ๋ฒ ํ ์ง๋ฅผ ์ ํ๋ ๊ฐ์ด์๋ค.
์ด ๋ ๊ฐ์ ๋ชจ๋ธ์ด ์ง์ ํ์ตํด์ ๋ฐฐ์ฐ๋ ๊ฒ ์๋๋ผ ๋ชจ๋ธ์ ๋ง๋๋ ์ฌ๋์ด ์ ํด์ค์ผ ํ๋ค.
์ด์ฒ๋ผ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ํ์ต์ํค๊ธฐ ์ ์ ์ฌ๋์ด ๋ฏธ๋ฆฌ ์ ํด์ค์ผ ๋๋ ๋ณ์๋ค์ ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ผ๊ณ ํ๋ค.
ํ์ดํผ ํ๋ผ๋ฏธํฐ์ ์ด๋ค ๊ฐ์ ๋ฃ๋๋์ ๋ฐ๋ผ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ํฐ ์ฐจ์ด๊ฐ ์์ ์ ์๊ธฐ ๋๋ฌธ์ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ต๋ํ ๋์ฌ์ฃผ๋ ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ณ ๋ฅด๋ ๊ฒ ๊ต์ฅํ ์ค์ํ๋ค.
๊ทธ๋ฌ๋ฉด ์ด์ ์ข์ ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ณ ๋ฅด๋ ๋ฐฉ๋ฒ ์ค ํ๋์ธ ๊ทธ๋ฆฌ๋ ์์น์ ๋ํด์ ์์๋ณด์.
๊ทธ๋ฆฌ๋ ์์น๋ ์ ํด์ค์ผ ํ๋ ๊ฐ ํ์ดํผ ํ๋ผ๋ฏธํฐ์ ๋ฃ์ด๋ณด๊ณ ์ถ์ ํ๋ณด ๊ฐ์ ๋ช ๊ฐ์ฉ ์ ํ ๋ค, ๋ชจ๋ ํ๋ณด ๊ฐ์ ์กฐํฉ์ผ๋ก ๋ชจ๋ธ์ ํ์ต์์ผฐ์ ๋ ์ฑ๋ฅ์ด ๊ฐ์ฅ ์ข์๋ ํ์ดํผ ํ๋ผ๋ฏธํฐ ์กฐํฉ์ ๊ณ ๋ฅด๋ ๋ฐฉ์์ด๋ค.
๊ทธ๋ฆผ์ผ๋ก ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.

๊ฐ ํ์ดํผ ํ๋ผ๋ฏธํฐ ํ๋ณด ๊ฐ๋ค์ ๋ชจ๋ ์กฐํฉ์ผ๋ก ๋ชจ๋ธ์ ์ฑ๋ฅ์ ํ๊ฐํ์ ๋ ๋์ฌ ์ ์๋ ํ๋ ์์ ๊ฐ๋ค. (์ด๋ ์ฑ๋ฅ์ k-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ์ฌ์ฉํด์ ์กฐ๊ธ ๋ ์ ํํ๊ณ ๊ณตํํ๊ฒ ๊ณ์ฐํ๋ค.)
๊ทธ๋ฆฌ๊ณ ๊ทธ ์ฑ๋ฅ๋ค ์ค ๊ฐ์ฅ ์ฑ๋ฅ์ด ์ข์(ํ๊ท ์ ๊ณฑ ์ค์ฐจ๊ทผ์ด ๋ฎ์์๋ก ์ฑ๋ฅ์ด ์ข๋ค.) ํ์ดํผ ํ๋ผ๋ฏธํฐ ์กฐํฉ์ ์ ํํ๋ฉด ๋๋ค.
์ด๋ฐ ์์ผ๋ก ํ๋ก Grid(๊ฒฉ์ ๋ชจ์)๋ฅผ ๋ง๋ค๊ณ , ์ฌ๊ธฐ์ ์ฑ๋ฅ์ด ๊ฐ์ฅ ์ข์ ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ์ด๊ธฐ ๋๋ฌธ์ Grid search๋ผ๊ณ ๋ถ๋ฅธ๋ค.
ํ์ดํผ ํ๋ผ๋ฏธํฐ๊ฐ 2๊ฐ ์ด์์ผ ๋๋ ๋๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ชจ๋ ์กฐํฉ์ ํ์ธํ ๋ค ์ฑ๋ฅ์ด ๊ฐ์ฅ ์ ๋์ค๋ ํ์ดํผ ํ๋ผ๋ฏธํฐ ์กฐํฉ์ ์ ํํ๋ฉด ๋๋ค.
์ฝ๋๋ ์๋์ ๊ฐ๋ค.
from sklearn.linear_model import Lasso
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import PolynomialFeatures
from sklearn.model_selection import GridSearchCV
from math import sqrt
import numpy as np
import pandas as pd
admission_df = pd.read_csv('../data/admission_data.csv')
X = admission_df.drop('Chance of Admit ', axis=1)
polynomial_transformer = PolynomialFeatures(2) # 2์ฐจ์ ๋ณํ๊ธฐ ์ ์
polynomial_features = polynomial_transformer.fit_transform(X.values)
features = polynomial_transformer.get_feature_names_out(X.columns)
X = pd.DataFrame(polynomial_features, columns=features)
y = admission_df[['Chance of Admit ']]
hyper_parameter = { # ๊ฐ ํ์ดํผ ํ๋ผ๋ฏธํฐ์ ํ๋ณด๊ตฐ๋ค์ ๋ด์ ๋์
๋๋ฆฌ
'alpha': [0.01, 0.1, 1, 10],
'max_iter': [100, 500, 1000, 1500, 2000]
}
lasso_model = Lasso()
hyper_parameter_tuner = GridSearchCV(lasso_model, hyper_parameter, cv=5) # ์ฌ์ฉํ ๋ชจ๋ธ, ์คํํด๋ณผ ํ์ดํผ ํ๋ผ๋ฏธํฐ ๊ฐ๋ค, ๊ฐ ์ฑ๋ฅ ํ๋จ์ ๋ช ๊ฒน ๊ต์ฐจ ๊ฒ์ฆ์ ํ ๊ฑด์ง
hyper_parameter_tuner.fit(X, y) # hyper_parameter_tuner์ X, y๋ฅผ ๋ฃ์ด์ ํ์ดํผ ํ๋ผ๋ฏธํฐ ํ๋ณด๋ค ์ค ์ด ๋ฐ์ดํฐ์ ์๋ง๋ ์ต์ ์ ์กฐํฉ์ ์ฐพ๋๋ค.(fit ํ๋ค.)
hyper_parameter_tuner.best_params_ # ์ต์ ์ ํ์ดํผ ํ๋ผ๋ฏธํฐ ์กฐํฉ ํ์ธ
๊ฒฐ๊ณผ:
{'alpha': 1, 'max_iter': 100}
์ถ์ฒ: ์ฝ๋์