ML 에는 Under-fitting 문제와 Over-fitting 문제가 존재한다.
그 중 학습 데이터에 과도하게 맞춰진 나머지,
테스트 데이터에 대한 예측 정확도가 떨어지는 문제인 Overfitting 문제를 해결하기 위해
교차 검증 , Cross Validation 을 수행한다.
그 중 K 폴드 교차 검증과 Stratified K 폴드 교차 검증을 정리하고자 한다.
K 폴드 교차 검증은 전체 데이터 셋을 N 등분하여 데이터 셋 N개로 소분한 다음,
학습 데이터 세트 N-1 개와 테스트 데이터 세트 1개를 가지고 검증을 반복한다.
검증을 반복할 때마다 테스트 데이터 세트와 학습 데이터 세트 구성을 변경한다.
Stratified K 폴드 교차 검증은
데이터 셋의 분포가 고르지 못한 경우,
데이터 셋을 N 등분 하면 어떤 하위 데이터 셋은 특정 데이터가 편중되어 있을 가능성이 높다.
편중된 데이터 셋을 가지고 학습 혹은 테스트가 이뤄지기 때문에 좋지 않다.
따라서 이 문제를 해결하기 위해 데이터 셋에 특정 데이터가 편중되지 않고 고르게 분포되도록 N등분하여
하위 데이터 셋으로 분할하여 K 폴드 교차 검증을 수행해야 한다.
그리고 이 방법을 Stratified K 폴드 교차 검증이라고 한다.
sklearn.datasets 에서 제공하는 데이터인 붓꽃(iris)의 데이터를 예시로 가져온다.
붓꽃의 품종: setosa, versicolor, virginica 마다
각 품종별 꽃받침 길이&넓이 꽃잎 길이&넓이를 저장한 데이터셋이다.
from sklearn.datasets import load_iris
from sklearn.model_selection import KFold, StratifiedKFold
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
import numpy as np
import pandas as pd
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df['label'] = iris.target
def get_label_names(label):
label_names=''
if label == 0:
label_names = iris.target_names[0]
elif label == 1:
label_names = iris.target_names[1]
else:
label_names = iris.target_names[2]
return label_names
# 'label' 의 값을 x 로 하여 get_label_names(x) 의 리턴값을 'label_names'로 한다.
iris_df['label_names'] = iris_df['label'].apply(lambda x : get_label_names(x))
iris_df.head(3)
# iris_df.describe()
일반적으로 KFold 로 데이터 셋 분할
kfold = KFold(n_splits=3)
iter=0;
for train_index, test_index in kfold.split(iris_df):
iter += 1
# DataFrame.iloc[index] 의 index를 리스트로 넘겨줄 수도 있다.
label_train = iris_df['label'].iloc[train_index]
label_test = iris_df['label'].iloc[test_index]
print("\n######")
print("{0} 번째 교차 검증".format(iter))
print(label_train)
print(label_test)
print("###")
print("학습 레이블 데이터 분포: ", label_train.value_counts())
print("검증 (테스트) 레이블 데이터 분포: ", label_test.value_counts())
가져온 iris 데이터셋은 행이 총 150개 (iris_df.describe() 를 하면 행이 몇 개인지 등 알 수 있다.)인데,
0 ~ 49번 행까지 는 0 ('setosa')
50 ~ 99번 행까지는 1 ('versicolor')
100 ~ 149번 행까지는 2('virginica')이다.
즉, 데이터 분포가 불규칙적인데,
150 개의 데이터를 n_splits = 3, 앞에서 부터 50개씩 묶어서 3개의 하위 데이터셋으로 분할했으므로
분할한 데이터셋도 값이 치우치게 된다.
Stratified_KFold 적용
stratified_kfd = StratifiedKFold(n_splits=3)
iter = 0
for train_index, test_index in stratified_kfd.split(iris_df, iris_df['label']):
iter += 1
label_train = iris_df['label'].iloc[train_index]
label_test = iris_df['label'].iloc[test_index]
print("\n######")
print("{0} 번째 교차 검증".format(iter))
# print(label_train)
# print(label_test)
print("###")
print("학습 레이블 데이터 분포: ", label_train.value_counts())
print("검증 (테스트) 레이블 데이터 분포: ", label_test.value_counts())
StratifiedKFold.split 의 파라미터는 분할할 데이터 셋 이외에도,
어떤 값을 기준으로 균등하게 데이터셋을 분할할지도 파라미터로 받는다.
-> 위의 예제에서는 iris_df['label']의 분포가 고르도록 데이터셋을 분할하도록 한다.
지도 학습은 크게 분류(classifier)와 회귀(regressor)로 나눌 수 있으며,
Classifier class 중 하나인 DecisionTreeClassifier 를 통해 모델을 학습시킨 후 ( fit() )
검증 데이터 셋에 대한 예측을 실시 ( prediction(X_test) )
예측값들에 대한 평균을 구한다.
random_state 는 랜덤시드값이다.
classifier = DecisionTreeClassifier(random_state=255)
s_KFold = StratifiedKFold(n_splits=3) # 교차 검증도 3 번 진행
iter=0;
cv_accuracy=[]
for train_index, test_index in s_KFold.split(iris_df, iris_df['label']):
X_train, X_test = iris.data[train_index], iris.data[test_index]
Y_train, Y_test = iris_df['label'].iloc[train_index], iris_df['label'].iloc[test_index]
# 모델 학습 및 예측
classifier.fit(X_train, Y_train)
prediction = classifier.predict(X_test)
iter += 1
# from sklearn.metrics import accuracy_score
accuracy = np.round(accuracy_score(Y_test, prediction), 4)
train_size = X_train.shape[0] # X_train 행갯수
test_size = X_test.shape[0] # X_test 행갯수
print("\n###")
print("{0} 번째 교차검증(CV) 정확도: {1}".format(iter, accuracy))
print("학습 데이터 크기 : {0}, 검증 데이터 크기 : {0}".format(train_size, test_size))
cv_accuracy.append(accuracy)
print("\n\n 평균 CV 정확도: ", np.mean(cv_accuracy))
근데 사실 교차 검증을 알아서 해주는 API 가 있다
# from sklearn.model_selection import train_test_split
#iris = load_iris()
from sklearn.model_selection import GridSearchCV
X_train, X_test, Y_train, Y_test = train_test_split(iris.data, iris.target, test_size = 0.2
,random_state=121)
classifier = DecisionTreeClassifier(random_state=255)
parameters = {'max_depth': [1, 2, 3], 'min_samples_split': [2,3]}
grid_dtree = GridSearchCV(classifier, param_grid = parameters, cv=3, refit=True)
grid_dtree.fit(X_train, Y_train)
scores_df = pd.DataFrame(grid_dtree.cv_results_)
scores_df.head(5)
그 중 하나가 cross_val_score()
from sklearn.model_selection import cross_val_score
iris = load_iris()
classifier = DecisionTreeClassifier(random_state=255)
scores = cross_val_score(classifier, iris.data, iris.target, scoring='accuracy', cv=3)
print(scores)
교차 검증과 하이퍼 파라미터 튜닝까지 같이 하는
GridSearchCV 도 있다.
# from sklearn.model_selection import train_test_split
#iris = load_iris()
from sklearn.model_selection import GridSearchCV
X_train, X_test, Y_train, Y_test = train_test_split(iris.data, iris.target, test_size = 0.2,random_state=121)
classifier = DecisionTreeClassifier(random_state=255)
parameters = {'max_depth': [1, 2, 3], 'min_samples_split': [2,3]}
grid_dtree = GridSearchCV(classifier, param_grid = parameters, cv=3, refit=True)
grid_dtree.fit(X_train, Y_train)
scores_df = pd.DataFrame(grid_dtree.cv_results_)
scores_df.head(5)
estimator = grid_dtree.best_estimator_
pred = estimator.predict(X_test)
print("accuracy of the best estimator: ", np.round(accuracy_score(Y_test, pred), 4))
'Study > Machine Learning 개론' 카테고리의 다른 글
4. ROC curve 와 AUC (0) | 2023.09.17 |
---|---|
3. Confusion matrix(오차행렬) 와 정밀도, 재현율, F1 score (1) | 2023.09.08 |
2. Data Preprocessing (0) | 2023.09.05 |