Data Analysis & ML/Machine Learning

[Machine Learning][머신러닝] 데이터셋 나누기와 교차검증

YSY^ 2020. 8. 26. 14:00

데이터셋 나누기

데이터셋 (Dataset)

  • Train 데이터셋 (훈련/학습 데이터셋)
    • 모델을 학습시킬 때 사용할 데이터셋.
  • Validation 데이터셋 (검증 데이터셋)
    • Train set으로 학습한 모델의 성능을 측정하기 위한 데이터셋
  • Test 데이터셋 (평가 데이터셋)
    • 모델의 성능을 최종적으로 측정하기 위한 데이터셋
    • Test 데이터셋은 마지막에 모델의 성능을 측정하는 용도로 한번만 사용되야 한다.
      • 학습과 평가를 반복하다 보면 모델이 검증때 사용한 데이터셋에 과적합되어 새로운 데이터에 대한 성능이 떨어진다.
        그래서 데이터셋을 train 세트, validation 세터, test 세트로 나눠 train 세트와 validation 세트로 모델을 최적화 한 뒤 마지막에 test 세트로 최종 평가를 한다.

 

Hold Out

  • 데이터셋을 Train set, Validation set, Test set으로 나눈다.
  • sklearn.model_selection.train_test_split() 함수 사용

Hold Out 예시

# iris - train, validation, test dataset으로 분리
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier #모델-결정트리
from sklearn.metrics import accuracy_score # 모델 평가함수 -> 정확도
from sklearn.model_selection import train_test_split # 데이터셋을 나누는 함수.
iris_data = load_iris()
iris_data.keys()
X, y = iris_data.data, iris_data.target
X.shape, y.shape

import numpy as np
# train, test로 분리
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.2, #기본:0.25
                                                    stratify=y, #target의 class비율에 맞춰서 분리
                                                    random_state=1)

print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)
print(np.unique(y_train, return_counts=True))

Train set을 Train/validation set으로 분리

X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, 
                                                  test_size=0.2, stratify=y_train, 
                                                  random_state=1)
X_train.shape, X_val.shape, X_test.shape

모델생성 및 평가

# 모델 생성
tree = DecisionTreeClassifier()
# 모델 학습 - train set
tree.fit(X_train, y_train)
# 예측 및 평가 - train/validation set
pred_train = tree.predict(X_train)
pred_val = tree.predict(X_val)

train_score = accuracy_score(y_train, pred_train)
val_score = accuracy_score(y_val, pred_val)
print("train set의 예측결과: {}, validation set의 예측결과: {}".format(train_score, val_score))
# ==> train set의 예측결과: 1.0, validation set의 예측결과: 0.9166666666666666

# 최종 평가 - test
pred_test = tree.predict(X_test)
test_score = accuracy_score(y_test, pred_test)
print("최종평가(test set): {}".format(test_score))
#==> 최종평가(test set): 0.9666666666666667

Holdout 방식의 단점

  • train/test 셋이 어떻게 나눠 지냐에 따라 결과가 달라진다.
    • 데이터가 충분히 많을때는 변동성이 흡수되 괜찮으나 수천건 정도로 적을 때는 문제가 발생할 수 있다.
  • 데이테셋의 양이 적을 경우 학습을 위한 데이터 양이 너무 적어 학습이 제대로 안될 수 있다.

 

K-겹 교차검증 (K-Fold Cross Validation)

  • 데이터셋을 K 개로 나눈 뒤 하나를 검증세트로 나머지를 훈련세트로 하여 모델을 학습시키고 평가한다. 나뉜 K개의 데이터셋이 한번씩 검증세트가 되도록 K번 반복하여 모델을 학습시킨 뒤 나온 평가지표들을 평균내서 모델의 성능을 평가한다.
  • 종류
    • K-Fold
    • Stratified K-Fold

 

KFold

  • 지정한 개수(K)만큼 분할한다.
from sklearn.model_selection import KFold

# K-Fold K-개수, fold 나눠진 데이터셋 - 5개
kfold = KFold(n_splits=5)
acc_train_list = [] # 평가지표들을 저장할 리스트
acc_test_list = []

ex = kfold.split(X)
print(type(ex))
next(ex) # 반복자의 다음 요소 구하기
# ==> (array([ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
#         43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,
#         56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,
#         69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,
#         82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,
#         95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107,
#        108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
#        121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
#        134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
#        147, 148, 149]),
# array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
#        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]))
for train_index, test_index in kfold.split(X):
    # index를 이용해 훈련/검증 데이터셋 추출
    X_train, y_train = X[train_index], y[train_index]
    X_test, y_test = X[test_index], y[test_index]

    # 모델생성
    tree = DecisionTreeClassifier()
    # 학습
    tree.fit(X_train, y_train)
    # 검증
    pred_train = tree.predict(X_train)
    pred_test = tree.predict(X_test)

    acc_train = accuracy_score(y_train, pred_train)
    acc_test = accuracy_score(y_test, pred_test)
    acc_train_list.append(acc_train)
    acc_test_list.append(acc_test)

acc_test_list, np.mean(acc_test_list)
# ==> ([1.0, 1.0, 0.8666666666666667, 0.9333333333333333, 0.8], 0.9199999999999999)

K-Fold의 문제점

  • 원 데이터셋의 row 순서대로 분할하기 때문에 불균형 문제가 발생할 수 있다.

 

Stratified K 폴드

  • 나뉜 fold 들에 label들이 같은(또는 거의 같은) 비율로 구성 되도록 나눈다.
from sklearn.model_selection import StratifiedKFold

s_fold = StratifiedKFold(n_splits=3)
acc_train_list = []
acc_test_list = []

ex = s_fold.split(X, y) #label의 class 별 동일한 분포로 나눈다.
type(ex)
for train_index, test_index in s_fold.split(X, y):
    X_train, y_train = X[train_index], y[train_index]
    X_test, y_test = X[test_index], y[test_index]

    # 모델생성
    tree = DecisionTreeClassifier()
    # 학습
    tree.fit(X_train, y_train)
    # 검증
    pred_train = tree.predict(X_train)
    pred_test = tree.predict(X_test)
    acc_train = accuracy_score(y_train, pred_train)
    acc_test = accuracy_score(y_test, pred_test)

    acc_train_list.append(acc_train)
    acc_test_list.append(acc_test)

acc_train_list, np.mean(acc_train_list)
#==> [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]

acc_test_list, np.mean(acc_test_list)
#==> ([0.98, 0.92, 0.96, 0.98, 0.92, 0.96], 0.9533333333333333)

cross_val_score( )

  • 데이터셋을 K개로 나누고 K번 반복하면서 평가하는 작업을 처리해 주는 함수
  • 주요매개변수
    • estimator: 학습할 평가모델객체
    • X: feature
    • y: label
    • scoring: 평가지표
    • cv: 나눌 개수 (K)
  • 반환값: array - 각 반복마다의 평가점수
from sklearn.model_selection import cross_val_score
tree = DecisionTreeClassifier()

score_list = cross_val_score(tree, X, y, scoring='accuracy', cv=3)

score_list
#==> array([0.98, 0.94, 0.98])
np.mean(score_list)
# ==> 0.9666666666666667
728x90
반응형