본문 바로가기
Machine Learning

[ML] Hyperparameter Tuning_ 교차검증

by ram_ 2023. 1. 5.

교차검증

과적합 : 모델이 학습 데이터에만 과도하게 최적화된 현상.
그로 인해 일반화된 데이터에서는 예측 성능이 과하게 떨어지는 현상.

지난번 와인 맛 평가에서 훈련용 데이터의 Acc 72.94,
테스트용 데이터는 Acc 71.61%였는데, 누가 이 결과가 정말 괜찮은 것인지 묻는다면?

나에게 주어진 데이터에 적용한 모델의 성능을 정확히 표현하기 위해서도 유용하다


import numpy as np
from sklearn.model_selection import KFold

X = np.array([
	[1, 2], [3, 4], [1, 2], [3, 4]
])
y = np.array([1, 2, 3, 4])

kf = KFold(n_splits=2)

print(kf.get_n_splits(X))
print(kf)

X와 y를 만들어주고 2등분해준다.

원래 데이터가 4개였으니 2-3을 train으로 쓰니 0-1을 test로 쓰고 / 다음번에는 0-1을 train, 2-3을 test로 쓰라는 의미이다.

이해를 위해 좀 더 정리하여 print해보았다.

 

크로스폴딩을 몇등분으로 할건지 지정해놓고 나면 인덱스를 반환받아와서 데이터를 분리시켜 학습을 진행할 수 있게 된다.

 


Use Wine Data

import pandas as pd

red_url = "https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/winequality-red.csv"
white_url = "https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/winequality-white.csv"

red_wine = pd.read_csv(red_url, sep=';')
white_wine = pd.read_csv(white_url, sep=';')

red_wine['color'] = 1.
white_wine['color'] = 0.
wine = pd.concat([red_wine, white_wine])

wine['taste'] = [1. if grade>5 else 0. for grade in wine['quality']]
X = wine.drop(['taste', 'quality'], axis = 1)
y = wine['taste']

wine 데이터를 불러와 교차검증을 구현해본다.

from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
import numpy as np

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13)

wine_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
wine_tree.fit(X_train, y_train)

y_pred_tr = wine_tree.predict(X_train)     
y_pred_test = wine_tree.predict(X_test)    

print('Train Acc : ', accuracy_score(y_train, y_pred_tr)) 
print('Test Acc : ', accuracy_score(y_test, y_pred_test))

** 데이터를 저렇게 분리하는 것이 최선인가 ? acc를 어떻게 신뢰할 수 있는가 ?

     -> KFold를 이용해 교차검증을 해보면 된다.

from sklearn.model_selection import KFold

kfold = KFold(n_splits=5)
wine_tree_cv = DecisionTreeClassifier(max_depth=2, random_state=13)

for train_idx, test_idx in kfold.split(X):
    print(len(train_idx), len(test_idx))

보통 5겹fold라고 n_splits는 5를 많이 쓴다. for문으로 print하여 분리된 데이터를 확인했다.

아직 학습이 되기 전 과정이다.

cv_accuracy = []

for train_idx, test_idx in kfold.split(X):
    X_train = X.iloc[train_idx]
    X_test = X.iloc[test_idx]
    y_train = y.iloc[train_idx]
    y_test = y.iloc[test_idx]
    wine_tree_cv.fit(X_train, y_train)
    
    pred = wine_tree_cv.predict(X_test)
    cv_accuracy.append(accuracy_score(y_test,pred))

cv_accuracy

각각의 데이터를 가져와서 fit 시키고 예측하여 정확도를 뽑아낸다.

결과값 [0.6007692307692307, 0.6884615384615385, 0.7090069284064665,

           0.7628945342571208, 0.7867590454195535] 

# 5split acc의 평균
np.mean(cv_accuracy)

70.9%의 정확도가 나왔다.

 


StratifiedKFold

from sklearn.model_selection import StratifiedKFold

skfold = StratifiedKFold(n_splits=5)
wine_tree_cv = DecisionTreeClassifier(max_depth=2, random_state=13)

cv_accuracy = []

for train_idx, test_idx in skfold.split(X, y):
    X_train = X.iloc[train_idx]
    X_test = X.iloc[test_idx]
    y_train = y.iloc[train_idx]
    y_test = y.iloc[test_idx]
    wine_tree_cv.fit(X_train, y_train)

    pred = wine_tree_cv.predict(X_test)
    cv_accuracy.append(accuracy_score(y_test,pred))

cv_accuracy

 

결과값 [0.5523076923076923, 0.6884615384615385, 0.7143956889915319,

            0.7321016166281755, 0.7567359507313318]

평균이 KFold보다 더 내려갔다. (내가 만든 모델의 성능이 생각보다 좋지 못할 수 있겠다는 점이 예측 가능하다.)

-> 그래서, 보통은 cross_val_score을 이용해 한번에 처리한다.

 

from sklearn.model_selection import cross_val_score

skfold = StratifiedKFold(n_splits=5)
wine_tree_cv = DecisionTreeClassifier(max_depth=2, random_state=13)

cross_val_score(wine_tree_cv, X, y, scoring=None, cv=skfold)

결과값 [0.55230769, 0.68846154, 0.71439569, 0.73210162, 0.75673595]

max_depth를 5로 바꿔서 돌렸더니 acc는 더 내려갔다. 보통 이런 긴 코드의 경우 어느부분이 달라져서 다른 출력값이 나오는지 한눈에 보기 어려우니, 함수로 만들어준다.

만약, train score도 함께 보고싶다면 cross_validate을 import 해온다.

acc를 비교해봤을때, 50%와 78%의 정확도 차이가 크니 과적합 현상이 일었다고 할 수 있다.

'Machine Learning' 카테고리의 다른 글

[ML] ROC Curve  (0) 2023.01.06
[ML] Hyperparameter Tuning  (0) 2023.01.06
[ML] Pipeline  (0) 2023.01.05
[ML] Wine Analysis _DecisionTree  (0) 2023.01.05
[ML] Encoder and Scaler  (0) 2023.01.04