본문 바로가기
Machine Learning

사이킷런으로 시작하는 머신러닝 - Model Selection 모듈(1)-

by rubyda 2020. 4. 9.
728x90
파이썬 머신러닝 완벽 가이드: 다양한 캐글 예제와 함께 기초 알고리즘부터 최신 기법까지 배우는/권철민 지음을 참고하여 공부하고 정리하는 스터디 포스팅입니다.

 

Model Selection 모듈

  • 사이킷런의 model_selection 모듈은 학습 데이터와 테스트 데이터를 분리하거나 교차 검증, 그리고 Estimator의 하이퍼 파라미터를 튜닝하기 위해서 다양한 함수와 클래스를 제공해 줍니다.

먼저 전체 데이터를 학습 데이터와 테스트 데이터로 분리해주는 train_test_split()부터 살펴보겠습니다.

 

1. 학습/테스트 데이터 세트 분리하기 - train_test_split()


  • 테스트 데이터를 사용하지 않고 학습 데이터만 학습하고 예측하면 어떠한 일이 벌어지는지 살펴보겠습니다.

In

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

iris=load_iris()
dt_clf=DecisionTreeClassifier()
train_data=iris.data
train_label=iris.target
dt_clf.fit(train_data,train_label)

# 학습 데이터로 예측 하기
pred=dt_clf.predict(train_data)
print('예측 정확도:',accuracy_score(train_label,pred))

out

예측 정확도: 1.0

정확도가 100%가 나왔습니다. 뭔가 이상하죠?? 이러한 결과가 나온 이유는 이미 학습한 데이터를 기반으로 예측을 하였기 때문입니다. 따라서 예측을 수행하는 데이터 세트는 학습용 데이터 세트가 아닌 다른 테스트 데이터 세트여야 합니다.

사이킷런에서는 train_test_split()를 사용해서 데이터 세트를 쉽게 분리할 수 있습니다. train_test_split(): 첫 번째 파라미터: 피처 데이터 세트, 두 번째 파라미터: 레이블 데이터 세트 그리고 선택적으로 다음 파라미터를 입력 받습니다.

  • test_size: 전체 데이터에서 테스트 데이터 세트 크기를 얼마로 샘플링할 것인가를 결정합니다.(디폴트는 0.25입니다),

  • train_size: 전체 데이터에서 학습용 데이터 세트 크기를 얼마로 샘플링할 것인가를 결정합니다.

  • shuffle: 데이터를 불리하기 전에 데이터를 미리 섞을지를 결정합니다. (디폴트는 True입니다) 데이터를 분산시켜서 좀 더 효율적인 학습 및 테스트 데이터 세트를 만들어 줍니다.

  • random_state: 호출할 때마다 동일한 학습/테스트용 데이터 세트를 생성하기 위해 주어지는 난수 값입니다. 이 파라미터를 지정하지 않으면 수행할 때마다 다른 학습/테스트 용으로 데이터를 생성하게 됩니다.

 

  • 붓꽃 데이터를 학습 데이터를 70%, 데스트 데이터를 30%로 분리하는 예제를 해보겠습니다.

In

from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

df_clf=DecisionTreeClassifier()
iris_data=load_iris()

x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target,
                                                    test_size=0.3, random_state=121)
df_clf.fit(x_train,y_train)
pred=df_clf.predict(x_test)
print('예측 정확도:{0:.4f}'.format(accuracy_score(y_test,pred)))

Out

예측 정확도:0.9556

 

 

위에서 말했듯이 학습 데이터와 예측 성능 평가를 위한 테스트 데이터가 필요합니다. 하지만 이 방법에서는 과적합(Overfiting)에 취약하다는 약점이 있습니다.

 

과적합(Overfiting) : 모델이 학습 데이터에만 과도하게 최적화 되어서 실제 예측을 다른 데이터로 시도했을 경우 예측 성능이 과도하게 떨어지는 현상을 말합니다.

 

이러한 문제를 개선하기 위해서 사용하는 교차검증에 대해서 배워보도록 하겠습니다. 

2. 교차 검증


교차 검증이란? 쉽게 말하자면 예를들어 시험을 보기 위해서 예비 모의고사를 여러 번 풀어보는 것이라고 생각하면 됩니다. 교차 검증은 데이터의 편중을 막기 위해서 별도의 여러개의 세트로 구성된 학습 데이터 세트와 검증 데이터 세트에서 학습과 평가를 수행하는 것입니다. 

 

대부분의 ML 모델에서 성능 평가는 교차 검증을 기반으로 1차 평가를 한 뒤에 최종적으로는 테스트 데이터세트에 적용해 평가하는 방식으로 진행됩니다. ML에서 사용되는 데이터 세트를 세분화 하면 학습, 검증, 테스트 3가지로 나눌 수 있습니다. 검증 데이터 세트는 최종 평가가 이루어지기 전에 학습된 모델을 다양하게 평가하는게 사용이 됩니다. 

2-1. K 폴드 교차 검증


  • K 폴드 교차 검증은 먼저 K개의 데이터 폴드 세트를 만들은 후 K번만큼 각 폴드 세트에 학습과 평가를 반복적으로 수행하는 방법입니다. 

아래 그림을 통해서 이해하기 쉽게 정리를 하였습니다.

 

K=5일 경우

총 5개의 폴드 세트에 5번의 학습과 검증 평가가 반복적으로 수행됩니다. 학습 데이터와 검증 데이터를 점진적으로 변경하면서 마지막 5번째까지 학습과 검증을 수행하게 되는것입니다. 5개의 예측 평가를 구하게 되면 최종적으로 평균을 취해서 결과가 반영이 됩니다.

 

사이킷런에서는 K 폴드 교차 검증 프로세스를 위해서 KFoldStrarifiedKFold 클래스를 제공합니다. 먼저 KFold 클래스를 이용해서 붓꽃 데이터 세트를 교차 검증및 예측 정확도를 알아보도록 하겠습니다.  

 

In

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

iris=load_iris()
features=iris.data
label=iris.target

iris 예제 데이터를 불러온 다음 독립변수와 종속변수의 값을 나누어서 저장을 해줍니다.

 

dt_clf=DecisionTreeClassifier(random_state=156)

split할 개수를 정해줍니다.

# 5개의 세트르 분리하는 KFold 객체와 폴드 세트별 정확도를 담을 리스트 객체 생성하기
Kfold=KFold(n_splits=5)
cv_accuracy=[]
print('붓꽃 데이터 크기:',features.shape[0])

 

Out

붓꽃 데이터 크기: 150

전체 데이터 세트는 150개입니다. 따라서 학습용 데이터 세트는 120개, 검증 테스트 데이터 세트는 30개로 분할하게 됩니다. 다음으로는 5개의 폴드 세트를 생성하는 KFold 객체의 split()을 호출하여 교차 검증 수행 마다 학습과 검증을 반복해 예측 정확도를 측정하도록 해보겠습니다.

 

In

n_iter=0

for train_index, test_index in Kfold.split(features):
    x_train, x_test = features[train_index], features[test_index]
    y_train, y_test = label[train_index], label[test_index]
    
    dt_clf.fit(x_train, y_train)
    pred = dt_clf.predict(x_test)
    n_iter += 1
    
    accuracy = np.round(accuracy_score(y_test,pred),4)
    train_size=x_train.shape[0]
    test_size=x_test.shape[0]
    print('\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기 {3}'.format(n_iter,accuracy, train_size, test_size))
    print('#{0} 검증 세트 인덱스:{1}'.format(n_iter, test_index))
    cv_accuracy.append(accuracy)
    
    print('\n## 평균 검증 정확도:',np.mean(cv_accuracy))

Out

#1 교차 검증 정확도 :1.0, 학습 데이터 크기: 120, 검증 데이터 크기 30
#1 검증 세트 인덱스:[ 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]

## 평균 검증 정확도: 1.0

#2 교차 검증 정확도 :0.9667, 학습 데이터 크기: 120, 검증 데이터 크기 30
#2 검증 세트 인덱스:[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]

## 평균 검증 정확도: 0.98335

#3 교차 검증 정확도 :0.8667, 학습 데이터 크기: 120, 검증 데이터 크기 30
#3 검증 세트 인덱스:[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]

## 평균 검증 정확도: 0.9444666666666667

#4 교차 검증 정확도 :0.9333, 학습 데이터 크기: 120, 검증 데이터 크기 30
#4 검증 세트 인덱스:[ 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]

## 평균 검증 정확도: 0.941675

#5 교차 검증 정확도 :0.7333, 학습 데이터 크기: 120, 검증 데이터 크기 30
#5 검증 세트 인덱스:[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]

## 평균 검증 정확도: 0.9

교차 검증시마다 검증 세트의 인덱스와 정확도들이 바뀌는것을 확인할 수 있습니다. 

다음 포스팅에서 이어서 정리를 해보겠습니다.