본문 바로가기
파이썬 라이브러리를 활용한 머신러닝

Model Evaluation and Improvement & Cross-Validation

by 일일과제중 2019. 12. 12.
반응형

 

Model Evaluation and Improvement for Supervised Learning

 

머신러닝 모델의 성능을 평가하고 올바른 하이퍼파라미터를 선택하는 방법을 다루도록 하겠습니다.

 

비지도 학습 모델을 평가하고 선택하는 일은 매우 정성적인 작업이므로 지도 학습인 회귀와 분류에 집중합니다.

 

지금까지 본 적 없는 새로운 데이터에 모델이 얼마나 잘 일반화되는지 측정하는 것이 주된 관심사입니다.

 

모델이 훈련 세트에 잘 맞는 것보다, 학습 과정에 없던 데이터에 대해 예측을 얼마나 잘 하느냐가 중요합니다.

 

지도 학습 모델을 평가하기 위해 데이터셋을 훈련 세트와 테스트 세트로 나눴습니다.

 

모델을 만들기 위해 훈련 세트에 fit 메서드를 적용했습니다.

 

모델을 평가하기 위해 테스트 세트에 predict 메서드를 적용했습니다. 

 

 

모델 평가 

 

교차 검증 (cross-vaidation) : 일반화 성능을 평가하기 위한 더 로버스트한 방법입니다.

 

평가 지표 (evaluation metrics) : 기본 성능 평가 외에도 분류나 회귀 성능을 평가하기 위해서 사용합니다.

 

 

하이퍼파라미터 선택

 

그리드 서치 (grid search) : 가장 좋은 일반화 성능을 얻기 위해서 지도 학습 모델의 매개변수를 조정하는 데 유용합니다. 

 

 

Cross-Validation

 

Training set (훈련 세트) : 모델의 파라미터를 학습합니다.

 

Validation set (검증 세트) : 모델의 하이퍼파라미터를 선택합니다.

 

Test set (테스트 세트) : 모델의 일반화 오차의 최종 평가를 위해 사용합니다.

 

훈련과 검증 세트에서 없던 새로운 데이터가 모델에서 얼마나 잘 작동할 수 있는지가 중요합니다.

 

흔한 실수 1: 훈련 세트에 대해서 최종 성능을 평가합니다.

 

흔한 실수 2: 검증 세트와 테스트 세트를 구분하지 않습니다.

 

그림1

 

 

데이터를 훈련, 검증, 테스트 세트로 나누는 이유는 지금까지 본 적 없는 새로운 데이터에 모델이 얼마나 잘 일반화되는지 측정하기 위해서입니다.

 

결과는 파티션을 위한 특정 랜덤 선택에 의해 좌우됩니다. 

 

세 개의 세트로 데이터를 파티션함으로써, 모델을 학습하는데 사용할 데이터 포인트의 숫자를 급격하게 줄일 수 있습니다. 

 

 

교차 검증은 일반화 성능을 평가하는 더 로버스트한 방법입니다.

 

교차 검증에서는 데이터를 여러 번 반복해서 나누고 여러 모델을 학습합니다.

 

교차 검증은 일반화 성능을 재기 위해 훈련 세트와 테스트 세트로 한 번 나누는 것보다 더 안정적이고 뛰어난 통계적 평가 방법입니다. 

 

 

k-Fold Cross-Validation

 

k-겹 교차 검증 : 교차 검증 방법 중 가장 널리 사용됩니다.

 

k는 특정 숫자인데 보통 5 또는 10을 사용합니다.

 

5-겹 교차검증을 하려면 데이터를 먼저 폴드라고 하는 (거의) 비슷한 크기의 '부분 집합' 다섯개로 나눕니다. 

 

그 다음 일련의 모델을 만듭니다.

 

첫 번째 모델은 첫 번째 폴드를 테스트 세트로 사용하고 나머지 (2-5) 폴드를 훈련 세트로 사용하여 학습합니다.

 

두 번째 모델은 두 번째 폴즈를 테스트 세트로 사용하고 폴드 (1, 3-5)를 훈련 세트로 사용하여 학습합니다.

 

이런 방법으로 폴드 3, 4, 5를 테스트 세트로 사용해 반복합니다.

 

이렇게 데이터를 훈련 세트와 테스트 세트로 나누는 다섯 번의 분할마다 정확도를 측정하여, 다섯 개의 정확도 값을 얻게 됩니다. 

 

보통 교차 검증의 정확도를 간단하게 나타내려면 평균을 사용합니다.

 

그림1

 

 

Stratified k-Fold Cross-Validation

 

분류일 경우 계층별 k-겹 교차 검증을 사용합니다. 

 

계층별 교차 검증에서는 폴드 안의 클래스 비율이 전체 데이터셋의 클래스 비율과 같도록 데이터를 나눕니다.

 

분류기의 일반화 성능을 측정할 때 k-겹 교차 검증보다 더 안정적인 계층별 k-겹 교차 검증을 사용하는 것이 좋습니다.

 

그림2

 

 

Leave-One-Out Cross-Validation

 

또 다른 교차 검증 방법으로 LOOCV도 자주 사용합니다.

 

LOOCV 교차 검증은 폴드 하나에 샘플 하나만 들어 있는 k-겹 교차 검증으로 생각할 수 있습니다. 

 

k는 데이터세트에 이는 데이터 포인트의 수입니다. 

 

각 반복에서 하나의 데이터 포인트를 선택해 테스트 세트로 사용합니다. 

 

데이터셋이 클 때는 시간이 매우 오래 걸리지만, 작은 데이터셋에서는 이따금 더 좋은 결과를 만들어 냅니다. 

 

 

Scikit-Learn의 교차 검증

 

from sklearn.datasets import load_iris
from sklearn.model_selection import cross_validate
from sklearn.linear_model import LogisticRegression
iris = load_iris()

 

아이리스 데이터셋을 사용합니다.

 

 

clf = LogisticRegression()
scores = cross_validate(clf, iris.data, iris.target, scoring='accuracy', cv=5,
                       return_train_score=True, return_estimator=True)

 

로지스틱회귀 모델을 만들고 5-겹 교차 검증을 진행합니다. 

 

cv 파라미터를 사용해서 폴드의 수를 바꿀 수 있습니다.

 

 

scores['train_score'], scores['test_score']

그림3

 

5-겹 교차 검증이므로 정확도 값이 5개 반환되었습니다. 

 

폴드 간 정확도가 상대적으로 높은 분산을 보입니다. (90% ~ 100%)

 

모델이 훈련에 사용된 특정 폴드에 매우 의존합니다. 

 

그러나 이는 데이터셋이 작은 규모라서 나온 결과일 수 있습니다. 

 

 

scores['estimator']

그림4

 

각 cv 분할에 대한 estimator objects입니다.

 

 

from sklearn.datasets import load_iris
from sklearn.model_selection import cross_validate, StratifiedKFold
from sklearn.linear_model import LogisticRegression
iris = load_iris()

 

Model_selection 모듈에서 계층별 교차 검증을 추가했습니다.

 

 

kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=1)

clf = LogisticRegression()
scores = cross_validate(clf, iris.data, iris.target, scoring='accuracy', cv=kfold,
                       return_train_score=True, return_estimator=True)

 

KFold 객체를 따로 만들어 cross_validate 함수의 cv 매개변수로 전달합니다.

 

shuffle 변수를 True로 지정하면 폴드를 나누기 전에 무작위로 섞습니다.

 

셔플링의 결과를 재현하기 위해 random_state를 지정합니다.

 

 

scores['train_score'], scores['test_score']

그림5

 

계층별 k-겹 교차 검증을 사용한 결과입니다.

 

 

from sklearn.tree import DecisionTreeClassifier

clf2 = DecisionTreeClassifier()
scores2 = cross_validate(clf2, iris.data, iris.target, scoring='accuracy', cv=kfold,
                       return_train_score=True, return_estimator=True)

 

결정 트리 분류 모델을 교차 검증해보겠습니다.

 

 

scores2['train_score'], scores2['test_score']

(array([1., 1., 1., 1., 1.]),

 array([0.9 , 0.967, 0.967, 1. , 0.967]))

 

결과입니다.

 

 

from sklearn.datasets import load_iris
from sklearn.model_selection import StratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
iris = load_iris()
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=1)
score_train = []
score_test = []
for train_idx, test_idx in kfold.split(iris.data, iris.target):
    
    X_train = iris.data[train_idx]
    y_train = iris.target[train_idx]
    X_test = iris.data[test_idx]
    y_test = iris.target[test_idx]
    
    clf = LogisticRegression()
    clf.fit(X_train, y_train)
    
    y_train_hat = clf.predict(X_train)
    score_train.append(accuracy_score(y_train, y_train_hat))
    y_test_hat = clf.predict(X_test)
    score_train.append(accuracy_score(y_test, y_test_hat))
score_train, score_test

그림6

 

split 메서드는 훈련과 테스트 세트로 데이터를 분할하기 위한 인덱스를 생성합니다.

 

 

from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_validate, StratifiedKFold
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import accuracy_score
iris = load_iris()
scaler = StandardScaler()
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=1)
score_train = []
score_test = []
for train_idx, test_idx in kfold.split(iris.data, iris.target):
    
    X_train = iris.data[train_idx]
    y_train = iris.target[train_idx]
    X_test = iris.data[test_idx]
    y_test = iris.target[test_idx]
    
    scaler.fit(X_train)
    X_train_scaled = scaler.transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    clf = MLPClassifier(max_iter=1000, random_state=0)
    clf.fit(X_train_scaled, y_train)
    
    y_train_hat = clf.predict(X_train_scaled)
    score_train.append(accuracy_score(y_train, y_train_hat))
    y_test_hat = clf.predict(X_test_scaled)
    score_test.append(accuracy_score(y_test, y_test_hat))
score_train, score_test

([0.9833333333333333, 0.9833333333333333, 1.0, 0.9833333333333333, 0.975],

 [0.9, 0.9666666666666667, 0.9, 1.0, 0.9666666666666667])

 

데이터 스케일링을 한 후 교차 검증을 진행했습니다. 

 

 

교차 검증의 장점

 

테스트 샘플에 각 샘플이 정확하게 한 번씩 들어옵니다.

 

교차 검증의 점수를 (그리고 평균값을) 높이기 위해서는 데이터셋에 있는 모든 샘플에 대해 모델이 잘 일반화되어야 합니다.

 

데이터를 여러 개로 나누면 모델이 훈련 데이터에 얼마나 민감한지 알 수 있습니다.

 

 

데이터를 더 효과적으로 사용할 수 있습니다.

 

train_test_split을 사용하면 보통 데이터 중 75%를 훈련 세트로 사용하고 25%를 평가에 사용합니다.

 

10-겹 교차 검증이라면 데이터의 9/10인 90%를 모델 학습에 사용합니다. 많은 데이터는 보통 더 정확한 모델을 만들어 냅니다.

 

 

교차 검증의 주요 단점은 연산 비용이 늘어난다는 것입니다.

 

모델을 k개 만들어야 하므로 데이터를 한 번 나눴을 때보다 대략 k배 더 느립니다. 

 

 

파이썬 라이브러리를 활용한 머신러닝 책과 성균관대학교 강석호 교수님 수업 내용을 바탕으로 요약 작성되었습니다.

반응형

'파이썬 라이브러리를 활용한 머신러닝' 카테고리의 다른 글

Evaluation Metrics and Scoring  (0) 2019.12.16
Grid Search  (2) 2019.12.13
Utilizing Expert Knowledge  (0) 2019.12.11
Automatic Feature Selection  (0) 2019.12.09
Univariate Nonlinear Transformations  (0) 2019.12.06

댓글