교차검증
과적합 : 모델이 학습 데이터에만 과도하게 최적화된 현상.
그로 인해 일반화된 데이터에서는 예측 성능이 과하게 떨어지는 현상.
지난번 와인 맛 평가에서 훈련용 데이터의 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 |