#!/usr/bin/env python3


불확실성 고려


confusion matrix와 classifier report는 예측 결과를 자세히 분석할 수 있도록 도와줍니다.

하지만 예측값은 model에 담긴 많은 정보가 이미 손실된 상태입니다.

대부분의 classifier는 확신을 가늠하기 위한 decision_function이나 predict_proba 메소드를 제공합니다.

예측을 만들어내는 것은 decision_function, predict_proba 출력의 critical value를 검증하는 것입니다.


binary search에서 decision_function은 0, predict_proba는 0.5를 critical value로 사용합니다.


다음 예는 음성 클래스 데이터 포인트 400개와 양성 클래스 데이터 포인트 50개로 이뤄진 불균형 데이터셋의 classifier report입니다.

from mglearn.plots import plot_decision_threshold

import matplotlib.pyplot as plt


plot_decision_threshold()

plt.show()

decision function의 heatmap과 critical value 변화에 따른 영향



classification_report 함수를 사용해서 두 클래스의 정밀도와 재현율을 평가해보겠습니다.

from mglearn.datasets import make_blobs

from sklearn.model_selection import train_test_split

from sklearn.svm import SVC

from sklearn.metrics import classification_report


x, y = make_blobs(n_samples=(400, 50), centers=2, cluster_std=[7, 2], random_state=22)

x_train, x_test, y_train, y_test = train_test_split(x, y, stratify=y, random_state=22)

svc = SVC(gamma=0.5) # degree=3, C=1, gamma='auto', kernel='rbf'

svc.fit(x_train, y_train)


rpt_result = classification_report(y_test, svc.predict(x_test))

print('{}'.format(rpt_result))

#              precision    recall  f1-score   support


#           0       0.92      0.91      0.91       100

#           1       0.36      0.38      0.37        13


# avg / total       0.85      0.85      0.85       113

클래스 1에 대해 36%, 재현율은 38%입니다. class 0의 샘플이 매우 많으므로 classifier는 class 0에 초점을 맞추고 있습니다.


만약 class 1의 재현율을 높이는게 중요하다고 가정하면

class 1로 잘못분류된 FP(False Positive)보다 TP(True Positive)를늘려야 한다는 뜻입니다.

svc.predict로 만든 예측은 이 조건을 만족하지 못했지만 critical value를 조정하여 class 1의 재현율을 높이도록 예측을 조정할 수 있습니다.


기본적으로 decision_function의 값이 0보다 크면 class 1로 분류 됩니다. 더 많은 데이터 포인트가 class 1로 분류되려면 critical value를 낮춰야 합니다.

y_pred_lower_threshold = svc.decision_function(x_test) > -0.8

rpt_result_adj = classification_report(y_test, y_pred_lower_threshold)

print('{}'.format(rpt_result_adj))

#              precision    recall  f1-score   support


#           0       0.94      0.87      0.90       100

#           1       0.35      0.54      0.42        13


# avg / total       0.87      0.83      0.85       113

class 1의 정밀도는 낮아졌지만 재현율은 높아졌습니다.


간단한 예제를 위해 test set의 결과를 바탕으로 critical value를 선택했습니다.

실제로는 test set를 사용하면 안되며, 다른 parameter처럼 test set에서 decision critical value를 선택하면 과도하게 낙관적인 결과가 나옵니다. 대신에 검증세트나 교차 검증을 사용해야 합니다.



참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido

#!/usr/bin/env python3


Binary Classifier Evaluation


binary clssifier는 널리 사용되고 개념도 쉬운 머신러닝 알고리즘이지만 이렇게 간단한 작업을 평가하는 데에도 주의해야할 점이 많습니다.

정확도를 잘못 측정하는 경우에 대해 살펴보면

binary clssifier에는 양성 클래스와 음성 클래스가 있으며 양성 클래스관심 클래스 입니다.




1. Error Type

테스트가 양성이면 건강, 음성 이면 암진단으로 생각할 수 있습니다.

모델이 항상 완벽하게 작동하는 것은 아니니, 잘못 분류할 때가 있습니다.


건강한 사람을 음성으로 분류하면 추가 검사를 받게 할 것이며 이를 false positive거짓 양성이라 합니다.

반대로 암에 걸린사람을 음성으로 분류하여 제대로 된 검사나 치료를 받지 못하게 할 수도 있습니다. 이는 위의 오류보다 더 치명적으로 다가옵니다. 이런 종류의 잘못된 예측은 false negative거짓 음성이라 합니다.

통계학에서 false positive를 type-I Error false negative를 type-II Error라고 합니다.

암진단에서는 false negative가 false positive보다 중요도가 높습니다.




2. imbalanced dataset불균형 데이터셋

이 두 종류의 에러는 두 클래스 중 하나가 다른 것보다 훨씬 많을 때 더 중요합니다.

어떤 아이템이 사용자에게 보여진 impression노출 데이터로 클릭을 예측하는 것입니다.

아이템은 광고일 수도 있고, 관련 기사나 기타 등등 여러가지 일 수도 있습니다.

목표는 특정 상품을 보여주면 사용자가 클릭을 할지(관심 대상인지)를 예측하는 것입니다.


사용자가 관심 있는 것을 클릭할 때까지 100개의 광고나 글을 보여줘야 한다면

이 때 클릭이 아닌 데이터 99개클릭 데이터 1개가 데이터셋으로 만들어집니다.


즉 샘플의 99%가 클릭 아님(음성), 1%가 클릭(양성) 클래스에 속합니다.

이렇게 한 클래스가 다른 것보다 훨씬 많은 데이터셋을 imbalanced datasets불균형 데이터셋이라고 합니다.


클릭을 99% 정확도로 예측하는 분류기를 만들었다고 하면 정확도는 꽤 높아보이지만 불균형 클래스를 고려하지 못했습니다.


즉 머신러닝 모델을 만들지 않고서도 무조건 '클릭 아님'으로 예측하면 그 정확도는 99%입니다.

이 말은 모델이 '좋은 모델', '무조건 클릭 모델' 중에 하나일 수 있다는 사실입니다.

따라서 정확도로는 이 둘을 구분하기가 어렵습니다.


예를 위해서 digits 데이터셋을 사용해 숫자 9를 다른 숫자와 구분해서 9:1의 불균형한 데이터셋을 만들어보겠습니다.


from sklearn.datasets import load_digits

from sklearn.model_selection import train_test_split


digits = load_digits()

y = digits.target == 9


x_train, x_test, y_train, y_test = \

  train_test_split(digits.data, y, random_state=0)


# 항상 다수인 클래스(여기서는 '9 아님')를 예측값으로 내놓는 DummyClassifier를 사용해서 정확도를 계산해보면

from sklearn.dummy import DummyClassifier

import numpy as np


dummy_majority = DummyClassifier(strategy='most_frequent')

dummy_majority.fit(x_train, y_train)

pred_most_frequent = dummy_majority.predict(x_test)


print('예측된 유니크 레이블 ==> {}'.format(np.unique(pred_most_frequent)))

print('test score ==> {:.3f}'.format(dummy_majority.score(x_test, y_test)))

# 예측된 유니크 레이블 ==> [False]

# test score ==> 0.896


거의 아무것도 학습하지 않고 약 90% 정확도를 얻었습니다. 생각보다 높은 정확도를 가지고 있습니다.

하지만 문제에 따라서는 그저 무조건 한 클래스를 예측하기만 해도 될 수 있습니다.

실제 분류기 DecisionTreeClassifier를 사용한 것과 비교해보면

DecisionTreeClassifier는 이전 포스팅을 참고하세요

[1]Decision Tree -- intro, [2]Decision Tree, [3]Decision Tree Regressor

from sklearn.tree import DecisionTreeClassifier


tree = DecisionTreeClassifier(max_depth=2)

tree.fit(x_train, y_train)

pred_tree = tree.predict(x_test)


print('test score ==> {:.3f}'.format(tree.score(x_test, y_test)))

# test score ==> 0.918


정확도로만 보면 DecisionTreeClassifier가 더미 clssifier보다 조금 나을 뿐입니다.

비교를 위해 LogisticRegression과 기본 DummyClassifier clssifier 두 개를 더 살펴보겠습니다.


DummyClassifier는 무작위로 선택하므로 훈련 세트와 같은 비율의 예측값을 만듭니다.

DummyClassifier의 stategy의 기본값은 stratified로 클래스 레이블의 비율과 같은 비율로 예측 결과를 만들지만 타깃값 y_test와는 다르므로 정확도는 더 낮아집니다.

from sklearn.linear_model import LogisticRegression


dummy = DummyClassifier() # strategy='stratified'

dummy.fit(x_train, y_train)

pred_dummy = dummy.predict(x_test)


print('예측된 유니크 레이블 ==> {}'.format(np.unique(pred_dummy)))

print('dummy score ==> {:.3f}'.format(dummy.score(x_test, y_test)))

예측된 유니크 레이블 ==> [False  True]

# dummy score ==> 0.820

# logreg = LogisticRegression(C=0.1)


logreg.fit(x_train, y_train)

pred_logreg = logreg.predict(x_test)


print('예측된 유니크 레이블 ==> {}'.format(np.unique(pred_logreg)))

print('logreg score ==> {:.3f}'.format(logreg.score(x_test, y_test)))

# 예측된 유니크 레이블 ==> [False  True]

# logreg score ==> 0.978


무작위로 예측하는 DummyClassifier는 결과가 안 좋습니다. 반면 LogisticRegression 은 매우 좋으나 DummyClassifier도 81.3%를 맞추었으므로 실제로 이 결과가 유용한지 판단하기가 매우 어렵습니다.

imbalanced datasets에서 예측 성능을 정량화하는 데 정확도는 적절한 측정 방법이 아니기 때문입니다.

특히 pred_most_frequent와 pred_dummy처럼, 빈도나 무작위 기반 예측보다 얼마나 더 나은지 알려주는 평가지표가 필요합니다.

모델을 평가하는 지표라면 이런 비상식적인 예측은 피할 수 있어야 합니다.




3. confusion matrix오차행렬

confusion matix오차행렬은 binary clssifier 평가 결과를 나타낼 때 가장 많이 사용하는 방법입니다.

LogisticRegression의 예측 결과를 confusion_matrix 함수를 사용해서 확인해보겠습니다.

from sklearn.metrics import confusion_matrix


pred_logreg = logreg.predict(x_test)

confusion = confusion_matrix(y_test, pred_logreg)


print('confusion matrix \n{}'.format(confusion))

# confusion matrix 

# [[401   2]

# [  8  39]]


confusion_matrix의 출력은 2x2 배열입니다. 행은 정답 클래스에 해당하고, 열은 예측 클래스에 해당합니다.

각 항목의 숫자는 행에 해당하는 클래스(여기서는 '9 아님'과 '9')가 얼마나 많이 열에 해당하는 클래스로 분류되었는지를 나타냅니다.

다음은 confusion matrix를 시각적으로 보여주는 코드입니다.

import mglearn

import matplotlib.pyplot as plt

import matplotlib


matplotlib.rc('font', family='AppleGothic')

plt.rcParams['axes.unicode_minus'] = False


mglearn.plots.plot_confusion_matrix_illustration()

plt.show()

'nine'과 'not nine' 분류문제의 confusion matrix

>> confusion matrix의 대각선 성분은 정확히 분류된 경우고, 다른 항목은 한 클래스의 샘플들이 다른 클래스로 잘못 분류된 경우가 얼마나 많은지를 보여줍니다.



숫자 9를 양성 클래스로 정의하면 confusion matrix의 항목을 앞서 이야기한 false positive와 false negative로 연결할 수 있습니다.


true positive, false positive, true negative, false negative로 분류하고 약자로

TP, FP, TN, FN이라고 하면

mglearn.plots.plot_binary_confusion_matrix()

plt.show()

binary classifier의 confustion matrix


이제 이 confusion matrix를 사용하여 앞서 만든 모델들

1. DummyClassifier 2개와

2. DecisionTreeClassifier

3. LogisticRegression을 비교해보겠습니다.

pred_most_frequent = dummy_majority.predict(x_test)

pred_dummy = dummy.predict(x_test)

pred_tree = tree.predict(x_test)

pred_logreg = logreg.predict(x_test)


print('dummy model based on frequency')

print(confusion_matrix(y_test, pred_most_frequent))

print('\nrandom dummy model')

print(confusion_matrix(y_test, pred_dummy))

print('\ndecision tree')

print(confusion_matrix(y_test, pred_tree))

print('\nlogistic regression')

print(confusion_matrix(y_test, pred_logreg))


# dummy model based on frequency

# [[403   0]

#  [ 47   0]]


# random dummy model

# [[365  38]

#  [ 40   7]]


# decision tree

# [[390  13]

#  [ 24  23]]


# logistic regression

# [[401   2]

#  [  8  39]]


confusion_matrix를 보면 pred_most_frequent에서 잘못된 것이 보입니다.

항상 동일한 클래스를 예측하기 때문입니다.

반면에 pred_dummy는 특히 FN과 FP보다 TP가 매우 적고, TP보다 FP가 매우 많습니다.

pred_logreg는 거의 모든 면에서pred_tree보다 낫습니다.


이 행렬의 모든 면을 살펴보면 많은 정보를 얻을 수 있지만, 매우 수동적이며 정성적인 방법입니다.

'모델 평가와 성능 향상 > 평가 지표와 측정' 카테고리의 다른 글

불확실성 고려  (0) 2018.04.20

#!/usr/bin/env python3


nested cross-validation


GridSearchCV를 사용할 때 데이터를 train set와 test set로 한 번만 나누기 때문에, 결과가 불안정하고 테스트 데이터의 분할에 크게 의존합니다. 

이런 문제를 해결하기 위해 cross-validation 방식을 사용할 수 있습니다.

이를 nested cross-validation중첩교차검증이라 합니다.


nested cross-validation에서는 바깥쪽 루프에서 데이터를 train set와 test set로 나눈 여러개의 fold폴드를 만듭니다. 각 fold의 train set에 대해 grid search를 실행하며, 이 때 바깥쪽 루프에서 분할된 fold의 train set마다 optimal parameter가 다를 수 있습니다.

그런 다음 바깥쪽에서 분할된 fold의 test set의 점수를 optimal parameter 설정을 사용해 각각 측정합니다.


이 방법은 모델이나 parameter 설정이 아닌 테스트 점수의 목록을 만들어주고, grid search를 통해 찾은 optimal parameter가 모델을 얼마나 잘 일반화시키는지 알려줍니다.


새로운 데이터에 적용할 모델을 만드는 것이 아니니, nested cross-validation은 미래의 데이터에 적용하기 위한 예측 모델을 찾는데는 거의 사용하지 않습니다. 그러나 특정 데이터셋에서 주어진 모델이 얼마나 잘 일반화되는지 평가하는데 유용한 방법입니다.


GridSearchCV의 객체를 모델로 삼아 cross_val_score 함수를 호출하면 됩니다.

# library import

from sklearn.datasets import load_wine

from sklearn.model_selection import GridSearchCV, cross_val_score

from sklearn.svm import SVC


# datasets

wine = load_wine()


# create object

values = [0.001, 0.01, 0.1, 1, 10, 100]

param_grid = {'C':values, 'gamma':values}


svc= SVC()


# grid search

grid_search = GridSearchCV(svc, param_grid, cv=5)



scores = cross_val_score(grid_search, wine.data, wine.target, cv=5)


print('교차 검증 점수 ==> {}'.format(scores))

print('교차 검증 평균 점수 ==> {:.3f}'.format(scores.mean()))

# 교차 검증 점수 ==> [0.75675676 0.66666667 0.75       0.8        0.88235294]

# 교차 검증 평균 점수 ==> 0.771


>> SVC는 wine 데이터셋에서 평균 교차 정확도가 77.1%라고 말할 수 있습니다.


여기에서 안쪽 루프와 바깥쪽 루프에 각각 stratified 5 cross-validation을 사용했고

param_grid의 매개변수 조합은 6x6 = 36이고 이 때 만들어지는 모델은 36 x 5 x 5 = 900이므로

중첩 교차 검증은 연산 비용이 매우 큽니다


여기에서 안쪽 루프와 바깥쪽 루프에 같은 교차 검증 분할기를 사용했으며, 꼭 같을 필요는 없습니다.

위의 한 줄의 코드는 다음과 같이 표현할 수 있습니다.


# library import

import numpy as np


def nested_cv(x, y, inner_cv, outer_cv, Classifier, parameter_grid):

    outer_scores = []

    for train_samples, test_samples in outer_cv.split(x, y):

        best_params = {}

        best_score = -np.inf


        for parameters in parameter_grid:

            cv_scores = []


            for inner_train, inner_test in inner_cv.split(

                    x[train_samples], y[train_samples]):

                clf = Classifier(**parameters) # **kwargs:

                clf.fit(x[inner_train], y[inner_train])


                score = clf.score(x[inner_test], y[inner_test])

                cv_scores.append(score)


            mean_score = np.mean(cv_scores)

            if mean_score > best_score:

                best_score = mean_score

                best_params = parameters


        clf = Classifier(**best_params)

        clf.fit(x[train_samples], y[train_samples])

        outer_scores.append(clf.score(x[test_samples], y[test_samples]))

    return np.array(outer_scores)


# library import

from sklearn.model_selection import ParameterGrid, StratifiedKFold


scores = nested_cv(wine.data, wine.target, StratifiedKFold(5), StratifiedKFold(5), SVC, ParameterGrid(param_grid))

print('교차 검증 점수 ==> {}'.format(scores))

# cross-validation score ==> [0.64864865 0.66666667 0.63888889 0.68571429 0.79411765]


'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

asymmetric parameter with grid search  (0) 2018.04.05
cross-validation result analysis  (2) 2018.04.05
parameter overfitting  (0) 2018.04.04
simple grid search  (1) 2018.04.03

#!/usr/bin/env python3


asymmetric parameter with grid search


이전 포스팅 참조하기

SVC: [1]Kernelized Support Vector Machines


예를들어 SVCkernel parameter를 가지고 있는데 어떤 kernel을 사용하는지에 따라 관련있는 parameter들이 결정됩니다.

kernel='linear'이면 C parameter만 사용하고

kernel='rbf'이면 C와 gamma를 모두 사용합니다.


이런 경우에 kernel, C, gamma parameter의 모든 조합을 조사하는 것은 낭비입니다.


1. apply asymmetric parameter

이런 조건부 parameter조합을 적용하려면 GridSearchCV에 전달한 param_grid를 딕셔너리의 리스트로 만들기만 하면 됩니다.

# load library

from sklearn.datasets import load_breast_cancer

from sklearn.model_selection import train_test_split, KFold, GridSearchCV

from sklearn.svm import SVC


# datasets

cancer = load_breast_cancer()


# data paritition

x_train, x_test, y_train, y_test =\

  train_test_split(cancer.data, cancer.target,

                   random_state=0, test_size=0.3, stratify=cancer.target)


# create class

svc = SVC()

kfold = KFold(n_splits=5, shuffle=True, random_state=0)


values = [0.001, 0.01, 0.1, 1, 10, 100]

param_grid = [{'kernel':['rbf'], 'C':values, 'gamma':values},

               {'kernel':['linear'], 'C':values}]


grid_search = GridSearchCV(svc, param_grid, cv=kfold)

grid_search.fit(x_train, y_train)


# results

print('optimal parameter ==> {}'.format(grid_search.best_params_))

print('optimal parameter의 점수 ==> {:.3f}'.format(grid_search.best_score_))

print('optimal parameter로 일반화 점수 ==> {:.3f}'.format(grid_search.score(x_test, y_test)))

# optimal parameter ==> {'C': 100, 'kernel': 'linear'}

# optimal parameter의 점수 ==> 0.970

# optimal parameter로 일반화 점수 ==> 0.924



2. cv_results_ 결과 살펴보기

다음으로 cv_results_ 속성을 살펴보기 위해 pandas의 DataFrame으로 csv를 만든 후 일부만 보겠습니다.

# library import

import pandas as pd


results = pd.DataFrame(grid_search.cv_results_)


# write csv

results.T.to_csv('grid_search.cv_results_.csv')

cv_results_의 일부

>> kernel이 'linear'일 때는 'C'값만 변한 것을 확인할 수 있습니다.



참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido


'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

nested cross-validation  (1) 2018.04.05
cross-validation result analysis  (2) 2018.04.05
parameter overfitting  (0) 2018.04.04
simple grid search  (1) 2018.04.03

#!/usr/bin/env python3


cross-validation result analysis


이전 포스팅에서 parameter overfitting을 다뤘습니다.

GridSearchCV를 활용하여 최적 매개변수를 찾고, 이를 이용하여 모델의 성능을 향상시켰습니다. 

이번 포스팅에서는 GridSearchCV의 결과를 분석해보겠습니다.


cross-validation의 결과를 시각화 하면 검색 대상 매개변수가 모델의 일반화에 영향을 얼마나 주는지 알 수가 있습니다.

grid search는 연상 비용이 매우 크므로 비교적 간격을 넓게 하여 적은 수의 grid로 시작하는 것이 좋습니다.

그 다음 cross-validation의 결과를 분석하여 검색을 확장해 나갈 수 있습니다.

grid search의 결과는 cv_results_에 담겨 있어 DataFrame형태로 변환해서 보는 것이 도움이 됩니다.



1. iris 데이터셋으로 분석

# load library

from sklearn.datasets import load_iris

from sklearn.model_selection import train_test_split, KFold, GridSearchCV

from sklearn.svm import SVC


# datasets

iris = load_iris()


# data partition

x_train, x_test, y_train, y_test =\

  train_test_split(iris.data, iris.target,

                   random_state=0, test_size=0.3)


# create object

svc = SVC()

kfold = KFold(n_splits=10, shuffle=True, random_state=0) # stratified cross-validation


# param_grid

values = [0.001, 0.01, 0.1, 1, 10, 100, 1000]

param_grid = {'C':values, 'gamma':values}


# GridSearch

grid_search = GridSearchCV(svc, param_grid, cv=kfold)

grid_search.fit(x_train, y_train)


# result

print('최적 매개변수 점수 ==> {:.3f}'.format(grid_search.best_score_))

print('최적 매개변수 ==> {}'.format(grid_search.best_params_))

print('최적 매개변수의 테스트 점수 ==> {:.3f}'.format(grid_search.score(x_test, y_test)))

# 최적 매개변수 점수 ==> 0.981

# 최적 매개변수 ==> {'C': 10, 'gamma': 0.1}

# 최적 매개변수의 테스트 점수 ==> 0.978



import pandas as pd

results = pd.DataFrame(grid_search.cv_results_)

print('results \n{}'.format(results.head()))

DataFrame으로 표현한 grid_search.cv_results_

>> results의 행 하나는 특정한 하나의 매개변수 설정에 대응하며 각 설정에 대해 cross-validation의 모든 분할의 평균값, 표준편차를 포함한 결과가 기록되어 있습니다.

검색 대상 parameter grid가 2개 이므로, heatmap으로 시각화하기에 좋습니다.




2. 검색 결과를 heatmap으로 시각화

heatmap으로 시각화 하려면 각 parameter를 축으로 하는 numpy 배열을 만들어야합니다. 

7개의 grid를 사용했으므로 cross-validation의 평균을 7x7형태로 차원을 바꿔야합니다.

# library import

import mglearn

import matplotlib

import matplotlib.pyplot as plt

from mpl_toolkits.axes_grid1 import make_axes_locatable # colorbar의 크기를 정하기 위한 축 library


# matplotlib 설정

matplotlib.rc('font', family='AppleGothic'# 한글 출력

plt.rcParams['axes.unicode_minus'] = False # 축 -


# values = [0.001, 0.01, 0.1, 1, 10, 100, 1000]

# param_grid = {'C':values, 'gamma':values}


# 차원 변형

mean_score = results['mean_test_score'].reshape(7, 7) 


# 시각화

score_image = mglearn.tools.heatmap(mean_score, xlabel='gamma', xticklabels=param_grid['gamma'],

                      ylabel='C', yticklabels=param_grid['C'])


ax = plt.gca() # GetCurrentAxis

divider = make_axes_locatable(ax)

cax = divider.append_axes('right', size='5%', pad='5%')

plt.colorbar(score_image, cax=cax)

plt.show()


gamma와 C값에 따른 cross-validation 평균 점수의 heatmap


>> heatmap의 각 포인트는 특정 parameter 설정에 대한 cross-validation 실행에 대응됩니다. cross-validation의 정확도가 높을 수록 밝은색으로, 낮을 수록 어두운색으로 표현 됩니다. parameter에 따라서 다양한 색깔 포인트들이 존재하는 것은 그 만큼 모델이 parameter 설정에 민감하다는 것을 나타냅니다. 



3. parameter가 적절하게 선택되지 않은 예

parameter 설정에 민감하기 때문에 범위가 중요하며 검색 범위가 적절하게 선택되지 않은 예를 살펴보겠습니다.

# library import

import mglearn

import matplotlib

import matplotlib.pyplot as plt

from mpl_toolkits.axes_grid1 import make_axes_locatable # colorbar 조정하기 위한 그래프 축 library

import numpy as np


# subplots

_, axes = plt.subplots(1, 3)


# param_grid

param_grid_linear = {'C':np.linspace(1, 2, num=6),

                                 'gamma': np.linspace(1, 2, num=6)}


param_grid_log = {'C':np.linspace(1, 2, num=6),

                             'gamma':np.logspace(-3, 2, num=6)}


param_grid_range = {'C':np.logspace(-3, 2, num=6),

                                'gamma':np.logspace(-7, -2, num=6)}


# visualization

param_grid_sets = [param_grid_linear, param_grid_log, param_grid_range]    

for p, ax in zip(param_grid_sets, axes.ravel()):

    svc = SVC()

    kfold = KFold(n_splits=10, shuffle=True, random_state=0) # [1]stratified cross-validation(교차검증)-- 이전 포스팅 참조 하세요


    grid_search = GridSearchCV(svc, param_grid=p, cv=kfold) # GridSearch(estimator, param_grid, cv) 

    grid_search.fit(x_train, y_train)

    mean_score = grid_search.cv_results_['mean_test_score'].reshape(6, 6)


    score_image = mglearn.tools.heatmap(mean_score, xlabel='gamma', xticklabels=p['gamma'],

                         ylabel='C', yticklabels=p['C'], ax=ax)


axis = plt.gca() # GetCurrentAxis

divider = make_axes_locatable(axis)

cax = divider.append_axes('right', size='5%', pad='5%')

plt.colorbar(score_image, ax=axes.tolist() ,cax=cax)

plt.show()


적절하지 않은 parameter grid의 heatmap


>>  [1] 첫 번째 그래프는 점수 변화가 전혀 없어서 전체 parameter grid가 거의 같은 색입니다. 이런 결과는 parameter의 스케일 범위가 부적절할 때 발생합니다.

그러나 parameter 설정이 바뀌어도 아무런 변화가 없다면, 그 parameter가 중요하지 않은 것일 수도 있습니다.

처음에는 극단적인 값을 적용하고, parameter를 바꿔가며 정확도를 살펴보는 것을 추천합니다.


[2] 두 번째 그래프는 세로 띠 형태입니다. 이 것은 C에 상관없이 gamma만 정확도에 영향을 준다는 것입니다.

gamma는 적절한 범위지만 C는 그렇지 못한 것이며, 혹은 중요하지 않은 것일 수도 있습니다.


[3] 세 번째 그래프는C와 gamma  둘 모두에 따라 값이 변했습니다. 하지만 그래프 왼쪽 아래 부분에서는 아무런 변화가 없습니다. 최적치가 그래프의 경계에 있으니 이 경계 너머에 더 좋은 값이 있다고 생각할 수 있고, 이 영역이 포함되도록 parameter 검색 범위를 바꿔줘야 함


cross-validation 점수를 토대로 parameter grid를 튜닝하는 것은 아주 안전한 방법이며, parameter들의 중요도를 확인하는데도 좋습니다. 그러나 최종 테스트 세트를 대상으로 여러 parameter 범위를 테스트해서는 안됩니다.


여태까지 대칭적 parameter grid만 탐색했지만(C가 6개면, gamma도 6개) 다음 포스트에서는 비대칭 매개변수 grid 탐색을 다뤄 보겠습니다.



참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido

'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

nested cross-validation  (1) 2018.04.05
asymmetric parameter with grid search  (0) 2018.04.05
parameter overfitting  (0) 2018.04.04
simple grid search  (1) 2018.04.03

#!/usr/bin/env python3


parameter overfitting


이전 포스팅에서 평가를 위해서는 모델을 만들 때 사용하지 않은 독립된 데이터셋이 필요하다고 했습니다.

독립된 데이터셋을 사용하는 방법에는 2가지가 있습니다.

첫 번째는 train_test_split을 2번 사용하여 데이터를 3등분하는 것이고

두 번째는 cross-validation을 사용하는 것입니다.


우선 첫 번째 방법부터 살펴보겠습니다. 이 방법은 아래 소스를 통해 그래프로 확인할 수 있습니다.

# library import

import mglearn

import matplotlib

import matplotlib.pyplot as plt


# matplotlib 설정

matplotlib.rc('font', family='AppleGothic'# 한글폰트

plt.rcParams['axes.unicode_minus'] = False # 축 -


mglearn.plots.plot_threefold_split()

plt.show()

training set, validation set, test set의 3개의 폴드로 나눈 데이터



1. train_test_split을 이용한 iris데이터의 grid search

이번에는 iris 데이터로 살펴보겠습니다.

# load library

from sklearn.svm import SVC

from sklearn.model_selection import train_test_split

from sklearn.datasets import load_iris


# data load

iris = load_iris()


# train_test_split 1번

x_trainvalid, x_test, y_trainvalid, y_test=\

  train_test_split(iris.data, iris.target, random_state=0)


# train_test_split 2번

x_train, x_valid, y_train, y_valid =\

  train_test_split(x_trainval, y_trainval, random_state=1)  


print('x_train size:{}\nx_valid size:{}\nx_test size:{}'.format(x_train.shape, x_valid.shape, x_test.shape))

# x_train size:(84, 4)

# x_valid size:(28, 4)

# x_test size:(38, 4)


# grid search

values = [0.001, 0.01, 0.1, 1, 10, 100]

best_score = 0

for g in values:

    for c in values:

        svc = SVC(C=c, gamma=g).fit(x_train, y_train)

        scores = svc.score(x_valid, y_valid) # 검증세트로 svc를 평가


        if scores > best_score:

            best_score = scores

            best_param = {'C':c, 'gamma':g}

            

svc = SVC(**best_param).fit(x_trainvalid, y_trainvalid) # **kwargs: 딕셔너리 형태로 함수에 인자를 넘김

score_svc = svc.score(x_test, y_test)


print('최적 매개변수 점수 ==> {:.3f}'.format(best_score))

print('최적 매개변수 ==> {}'.format(best_param))

print('최적 매개변수에서 test ==> {:.3f}'.format(score_svc))

# 최적 매개변수 점수 ==> 0.964

# 최적 매개변수 ==> {'C': 10, 'gamma': 0.001}

# 최적 매개변수에서 test ==> 0.921


>> 최적 매개변수에서 최고점수는 96.4%이며 테스트 세트 점수는 92.1%입니다. 

새로운 데이터에 대해 92.1%만 정확하게 분류한다고 볼 수 있습니다.

테스트 세트로 둘 이상의 모델을 평가해서 그 중 더 나은 하나를 선택하는 것은 모델의 정확도를 매우 낙관적으로 추정하거나, 

overfitting이 생길 수 있으므로 주의해야합니다.


2. cross-validaion을 이용한 iris데이터의 grid search


일반화 성능을 더 잘 평가하려면 훈련 세트와 검증 세트를 한 번만 나누지 않고 

cross-validation을 사용해서 각 매개변수 조합의 성능을 평가할 수 있습니다.


cross-validation을 통해 어떤 매개변수가 선택되는지를 살펴보면

# library import

import mglearn

import matplotlib.pyplot as plt


mglearn.plots.plot_cross_val_selection()

plt.show()

cross-validation을 사용한 grid search의 결과


>> [0.001, 0.01, 0.1, 1, 10, 100]를 C와 gamma로 각각 설정한 후, cross-validation 에 한개씩, 모두 5개의 값을 계산합니다.

총 6x6x5 = 180개의 모델을 만들어서 모델 검정을 하기때문에 시간이 오래 걸립니다.


# library import

import numpy as np

from sklearn.svm import SVC

from sklearn.datasets import load_iris

from sklearn.model_selection import train_test_split


# datasets

iris = load_iris()


# data partition

x_train, x_test, y_train, y_test = \

  train_test_split(iris.data, iris.target,

                   random_state=0, test_size=0.3)


# grid search

values = [0.001, 0.01, 0.1, 1, 10, 100]

best_score = 0

for g in values:

    for c in values:

        svc = SVC(gamma=g, C=c).fit(x_train, y_train)

        kfold = KFold(n_splits=5, shuffle=True, random_state=0)

        scores = cross_val_score(svc, x_train, y_train, cv=kfold)

        score = np.mean(scores)


        if score > best_score:

            best_score = score

            best_param = {'gamma':g, 'C':c}


# 최적 매개변수로 모델을 다시 만듬             

svc = SVC(**best_param).fit(x_train, y_train)

print('최적 매개변수 점수 ==> {:.3f}'.format(best_score))

print('최적 매개변수 ==> {}'.format(best_param))

print('최적 매개변수에서 test ==> {:.3f}'.format(svc.score(x_test, y_test)))

# 최적 매개변수 점수 ==> 0.981

# 최적 매개변수 ==> {'gamma': 0.01, 'C': 100}

# 최적 매개변수에서 test ==> 0.978



cross-validation을 사용한 grid search를 매개변수 조정 방법으로 많이 사용하기 때문에

scikit-learn은 GridSearchCV를 제공합니다.


GridSearchCV는 딕셔너리 형태로 검색 대상 매개변수를 지정하며 필요한 모든 모델을 학습합니다. 아래 소스는 위의 소스와 같은 결과를 냅니다.

# library import

from sklearn.svm import SVC

from sklearn.datasets import load_iris

from sklearn.model_selection import train_test_split, GridSearchCV, KFold


# data load

iris = load_iris()


# data parition

x_train, x_test, y_train, y_test = \

  train_test_split(iris.data, iris.target,

                   random_state=0, test_size=0.3)


# create object

svc = SVC() # SVC모델 생성

kfold = KFold(n_splits=5, shuffle=True, random_state=0) # cross-validation 


values = [0.001, 0.01, 0.1, 1, 10, 100]

param_grid = {'gamma':values, 'C':values}  # GridSearchCV의 딕셔너리 생성


grid_search = GridSearchCV(svc, param_grid, cv=kfold)

grid_search.fit(x_train, y_train)


score = grid_search.score(x_test, y_test)

print('GridSearchCV를 이용한 최적 매개변수 점수 ==> {:.3f}'.format(grid_search.best_score_))

print('GridSearchCV를 이용한 최적 매개변수 ==> {}'.format(grid_search.best_params_))

print('GridSearchCV를 이용한 test점수 ==> {:.3f}'.format(score))

print('GridSearchCV를 이용한 최고 성능 모델 ==> \n{}'.format(grid_search.best_estimator_))

# GridSearchCV를 이용한 최적 매개변수 점수 ==> 0.981

# GridSearchCV를 이용한 최적 매개변수 ==> {'C': 10, 'gamma': 0.1}

# GridSearchCV를 이용한 test점수 ==> 0.978

# GridSearchCV를 이용한 최고 성능 모델 ==> 

#SVC(C=10, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma=0.1, kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False)


>> 이 소스는 더 간결해졌지만 많은 내용을 함축하고 있습니다.

다음에는 GridSearchCV를 통해 cross-validation 결과를 시각화 해보겠습니다.



참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido

'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

nested cross-validation  (1) 2018.04.05
asymmetric parameter with grid search  (0) 2018.04.05
cross-validation result analysis  (2) 2018.04.05
simple grid search  (1) 2018.04.03

#!/usr/bin/env python3


Simple Grid Search


머신러닝의 성능을 높이는 방법에는 여러가지가 있지만

여기서는 매개변수를 튜닝하여 일반화 성능을 높이는 것목표입니다.

가장 널리 사용하는 방법은 grid search그리드 서치 이며

관심있는 매개변수들을 대상으로 가능한 모든 조합을 시도해보는 것입니다.


SVM의 경우 

커널의 폭에 해당하는 gamma와 규제 매개변수 C가 중요합니다.

SVM에 더 자세한 정보는 이전 포스팅을 참조하세요

[1]Kernelized Support Vector Machines

매개변수 C와 gamma에 [0.001, 0.01, 0.1, 1, 10, 100] 값을 적용해보면

조합의 수는 총 6x6=36개가 나오며


모든 조합을 살펴보기 위해 SVM 매개변수 설정 테이블을 다음처럼 만들 수 있습니다.

매개 변수 설정 테이블


간단한 grid search의 경우는 아래처럼 코드를 짤 수 있습니다.

# library import

from sklearn.svm import SVC

from sklearn.model_selection import train_test_split

from sklearn.datasets import load_iris


# data load

iris = load_iris()


# data partition

x_train, x_test, y_train, y_test = \

  train_test_split(iris.data, iris.target,

                   test_size=0.3, random_state=0)


print('train set size:{}, test set size:{}'.format(x_train.shape, x_test.shape))

# train set size:(105, 4), test set size:(45, 4)


# grid search

best_score = 0

values = [0.001, 0.01, 0.1, 1, 10, 100]

for g in values:

    for c in values:

        svc = SVC(gamma=g, C=c).fit(x_train, y_train)

        score = svc.score(x_test, y_test)

        if score > best_score:

            best_score = score

            best_param = {'C':c, 'gamma':g}


print('best score ==> {:.3f}'.format(best_score))

print('best parameter ==> {}'.format(best_parameter))

# best score ==> 0.978

# best parameter ==> {'C': 100, 'gamma': 0.001}

>> grid search를 통해 C=100, gamma: 0.001일 때 가장 좋은 결과가 나온 것을 확인할 수 있습니다.

이 결과를 보면 이 데이터셋에서 모델 정확도가 97.8%라고 보고할 수 있습니다.


하지만 이런 주장은 다음과 같은 이유로 잘못될 수도 있습니다.

1. 이 정확도는 새로운 데이터까지 이어지지 않을 수 있습니다.

매개변수를 조정하기 위해 테스트 세트를 이미 사용했기 때문에 테스트세트는 모델이 얼마나 좋은지 평가하는 데 사용할 수 없습니다.

즉 평가를 위해서는 모델을 만들 때 사용하지 않은 독립된 데이터셋이 필요하고 

다음 장에서 독립된 데이터셋을 다루는 방법을 살펴보겠습니다.



참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido

'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

nested cross-validation  (1) 2018.04.05
asymmetric parameter with grid search  (0) 2018.04.05
cross-validation result analysis  (2) 2018.04.05
parameter overfitting  (0) 2018.04.04

#!/usr/bin/env python3


다양한 교차 검증 방법


1. LOOCVLeave-one-out cross-validation

LOOCV 교차 검증폴드 하나샘플 하나만 들어 있는 k-겹 교차 검증

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

특히 데이터셋이 클 때는 시간이 매우 오래 걸리지만, 작은 데이터셋에서는 좋은 결과를 만들어냄


# library load

from sklearn.datasets import load_iris

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import LeaveOneOut, cross_val_score, KFold


# dataset

iris = load_iris()


# create object

logreg = LogisticRegression() # model

loo = LeaveOneOut() # LeaveOneOut model


# test validation

# LOOCV

scores_loo = cross_val_score(logreg, iris.data, iris.target, cv=loo) 


# K-fold(5)

kfold = KFold(n_splits=5, random_state=0, shuffle=True)

scores_fold = cross_val_score(logreg, iris.data, iris.target, cv=kfold) # model, train, target, cross validation


# cv result

print('iris.data.shape \n{}'.format(iris.data.shape))

print('cv number of partition \n{}'.format(len(scores_loo)))

print('mean score_loocv \n{:.3f}'.format(scores_loo.mean()))

print('mean score_kfold \n{:.3f}'.format(scores_fold.mean()))


cv result


>> LOOCV가 K-fold보다 성능이 더 좋음을 알 수가 있음



2. shuffle-split cross-validation임의 분할 교차 검증

shuffle-split cross-validation에서는 

train_size만큼의 포인트로 train set를 만들고, test_size만큼(train set와 중첩되지 않는) 포인트로 test set를 만들도록 분할함

이 분할은 n_splits 횟수만큼 반복됨


# load library

import mglearn

import matplotlib.pyplot as plt

import matplotlib


# matplotlib 설정

matplotlib.rc('font', family='AppleGothic') # 한글출력

plt.rcParams['axes.unicode_minus'] = False # 축 -


mglearn.plots.plot_shuffle_split()

plt.show()


10개의 데이터 포인트에 train_size=5, test_size=2와 n_splits=4를 적용한 ShuffleSplit


>> train_size와 test_size에 정수를 입력하면 데이터포인트의 절대 갯수를

실수를 입력하면 전체 데이터에서의 비율을 의미


# iris데이터를 이용하여 shuffle-split cross-validation

# load library

from sklearn.model_selection import ShuffleSplit


# create object

shuffle_split = ShuffleSplit(test_size=0.5, train_size=0.5, n_splits=10) # ShuffleSplit 객체 생성


# cv test

scores = cross_val_score(logreg, iris.data, iris.target, cv=shuffle_split)


# cv test result

print('cv test score \n{}'.format(scores))

cv test score

>> 임의 분할 교차 검증은 반복 횟수를 훈련 세트나 테스트 세트의 크기와 독립적으로 조절해야 할때 유용함

또한 train_size와 test_size의 합을 전체와 다르게 함으로써 전체 데이터의 일부만 사용할 수 있음

이렇게 데이터를 subsampling부분 샘플링방식은 대규모 데이터셋으로 작업할 때 유용함



3. 그룹별 교차 검증

# load library

mglearn.plots.plot_group_kfold()

plt.show()

레이블에 기반한 GroupKFold분할


>> 이 그림에서 볼 수 있듯이 각 분할에서 한 그룹 전체가 훈련 세트 아니면 테스트 세트에 있음

그룹별 교차 검증의 자세한 정보는 아래 링크 참조

http://scikit-learn.org/stable/modules/cross_validation.html


데이터 안에 매우 연관된 그룹이 있을 때도 교차 검증을 널리 사용함

<<얼굴 사진에서 표정을 인식하는 시스템을 만들기 위해 100명의 사진을 모았다고 가정>>

한 사람을 찍은 여러 장의 사진이 각기 다른 표정을 담고 있음 ==>

이 데이터셋에 없는 사람의 표정을 정확히 구분할 수 있는 분류기를 만드는 것이 목표


같은 사람의 사진훈련 세트와 테스트 세트에 모두 나타날 수 있으므로 그룹별 교차겸증을 하는것이 타당


새 얼굴에 대한 일반화 성능을 더 정확하게 평가하려면

훈련 세트와 테스트 세트에 서로 다른 사람의 사진이 들어가도록 해야함


이를 위해 사진의 사람이 누구인지 기록한 배열을 

groups 매개변수로 전달 받을 수 있는 GroupKFold를 사용할 수 있음

groups 배열은 훈련 세트와 테스트 세트를 만들 때 분리되지 않아야 할 그룹을 지정하는 것이라 클래스 레이블과는 다름


데이터에 그룹에 있는 예로는 의료분야가 일반적

여기서는 같은 환자로부터 얻은 여러 샘플을 가지고 새로운 환자에게 일반화하는 것이 목적


비슷하게 음성 인식에서도 데이터셋에 같은 사람의 목소리가 여러 개 녹음되어 있을 수 있으며, 

관심사항은 새로운 사람의 대화를 인식하는 것


# load library

from sklearn.model_selection import GroupKFold

from sklearn.datasets import make_blobs


# datasets

x, y = make_blobs(n_samples=12, random_state=0)

plt.scatter(x[:, 0], x[:, 1], c=y)

plt.xlabel('feature 0')

plt.ylabel('feature 1')

plt.show()


make_blobs로 만든 인위적 데이터

>> 인위적으로 만든 데이터셋에 group 배열로 그룹을 지정하는 방법

데이터셋은 12개의 포인트로 이뤄져 있고 groups는 각 데이터 포인트에 대해 각 포인트가 어떤그룹(ex. 환자)에

속하는지를 나타냄

4개의 그룹을 나타내고 있으며 처음 3개의 샘플을 첫번째 그룹, 다음 4개는 두번째 그룹을 나타내는 식

샘플 데이터를 그룹으로 정렬할 필요는 없음


# create object

gkfold = GroupKFold(n_splits=3) # GroupKFold

groups = [0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3] # group class


# cv test

scores = cross_val_score(logreg, x, y, groups, cv=gkfold)


# cv test result

print('cv test score \n{}'.format(scores))

cv test score


#!/usr/bin/env python3


scikit-learn에서의 cross-validation(교차검증)


scikit-learn에서 교차 검증은 model_selection 모듈cross_val_score 함수로 구현되어 있음


1. iris 데이터셋에 cross-validation을 간단하게 적용하기

iris 데이터셋에 LogisticRegression을 평가해보면

LogisticRegression 이전 포스팅 참조하기: [1]Logistic Regression[1], [2]Logistic Regression[2]


# library import

from sklearn.model_selection import cross_val_score

from sklearn.datasets import load_iris

from sklearn.linear_model import LogisticRegression


# dataset

iris = load_iris()

logreg = LogisticRegression()


scores = cross_val_score(logreg, iris.data, iris.target, cv=5) # model, train, target, cross validation


print('cross-val-score \n{}'.format(scores))

print('cross-val-score.mean \n{:.3f}'.format(scores.mean()))


5겹 교차검증 결과와 평균


>> 교차 검증 평균값으로 우리는 이 모델의 정확도가 대략 96%일 것으로 기대할 수 있음

5겹 교차 검증이 만든 5개의 값을 모두 보면 100%에서 90%까지 폴드에 따라 비교적 차이가 큼

이는 모델이 훈련에 사용한 폴드에 매우 의존적이거나 데이터셋이 작기 때문일 수 있음



교차 검증의 장점은 train_test_split와 비교해보면

train_test_split는 데이터를 무작위로 나눔. 데이터를 무작위로 나눌 때

훈련 세트 ==>  분류하기 어려운 샘플

테스트세트 ==> 분류하기 쉬운 샘플

테스트 세트의 정확도는 비현실적으로 높게 나올 것입니다. 

반대의 경우라면 테스트 세트의 정확도는 비현실적으로 낮게 나옴


그러나 교차 검증을 사용하면 테스트 세트에 각 샘플이 정확하게 한번씩 들어가고

각 샘플은 폴드 중 하나에 속하며 각 폴드는 한번씩 테스트 세트가 됨 

그렇기 때문에 교차 검증의 점수를 높이기 위해서는 데이터 셋에 있는 모든 샘플에 대해 모델이 잘 일반화 되어야 함


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

iris데이터셋에서 90%~ 100%의 정확도를 얻음. 최악의 경우와 최선의 경우를 짐작할 수 있음


교차 검증의 주요 단점연산 비용이 늘어남

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



2. 계층별 k-겹 교차 검증과 그 외 전략들


# load library

import matplotlib.pyplot as plt

import matplotlib

from sklearn.datasets import load_iris

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import cross_val_score

import numpy as np


# data load

iris = load_iris()


print('iris label \n{}'.format(iris.target))

print('''iris label's bin \n{}'''.format(np.bincount(iris.target)))

iris label과 bin


>>첫번째 1/3은 클래스 0, 두번째 1/3은 클래스1 마지막 1/3은 클래스2 임을 확인할 수 있음

첫번째 폴드는 클래스 0만 가지고 있으므로, 첫 번째 반복에서 테스트세트는 클래스 0만을, 훈련세트는 클래스 1과 2만을 가지게 됨 

세번의 반복 모두 훈련 세트와 테스트 세트의 클래스가 다르므로 데이터셋에서 3-겹 교차 검증의 정확도는 0이 됨



단순한 k-겹 교차검증에는 문제가 있으니 stratified k-fold cross-validation계층별 k-겹 교차 검증을 사용함


# library import

import mglearn


# matplotlob 설정

matplotlib.rc('font', family='AppleGothic'# 한글출력

plt.rcParams['axes.unicode_minus']=False # 축 -


mglearn.plots.plot_stratified_cross_validation()

plt.show()

클래스 레이블 순서대로 정렬된 데이터에서 기본 교차 검증과 계층별 교차 검증 비교


계층별 교차 검증은 폴드 안의 클래스 비율이 데이터셋의 클래스 비율과 같도록 데이터를 나눔

예를 들어 샘플의 90%가 클래스 A이고 10%가 클래스 B에 속한다면, 계층별 교차 검증은 각 폴드에 클래스 A샘플이 90%, 클래스 B 샘플이 10%가 되도록 만듬



2. 교차 검증 상세 옵션


그러나 scikit-learn에서는 cv 매개변수에 교차 검증 분할기cross-vailidation splitter를 전달함으로써 데이터를 분할할 때 더 세밀하게 제어할 수 있음

대부분의 경우 회귀에서는 k-겹 교차 검증, 분류에서는 계층별 k-겹 교차검증의 기본값이 잘 작동함


하지만 조금 다른 전략이 필요할 때가 있음. 예를 들어 다른사람의 결과를 재현하기 위해 분류 데이터셋에 기본 k-겹 교차 검증을 사용해야 할때

이렇게 하려면 먼저 model_selection에서 KFold 분할기를 임포트하고 원하는 폴드 수를 넣어 객체를 생성해야 함


# library import

from sklearn.model_selection import KFold


kfold = KFold(n_splits=5) # KFold 객체 생성

logreg = LogisticRegression() # 모델 객체 생성


for n in [3, 5]:

    kfold = KFold(n_splits=n)

    scores = cross_val_score(logreg, iris.data, iris.target, cv=kfold)

    print('n_splits={}, cross validation score: {}'.format(n, scores))

n_splits에 따른 교차 검증 테스트 점수

>> n_splits=3일 때 각 폴드는 iris 데이터셋의 클래스 중 하나에 대응하므로 아무것도 학습할 수가 없음

계층별 폴드를 만드는 대신 이문제를 해결하는 방법은 

데이터를 섞어서 샘플의 순서를 랜덤하게 만드는것(KFold의 shuffle 매개변수True)


데이터를 섞을 때 random_state를 고정해서 똑같은 작업을 재현할 수있음

그렇지 않으면 cross_val_score를 실행할 때마다 폴드가 바뀌어 매번 결과가 달라짐


for n in [3, 5]:

    kfold = KFold(n_splits=n, shuffle=True, random_state=0)

    scores = cross_val_score(logreg, iris.data, iris.target, cv=kfold)

    print('n_splits={}, cross validation score: {}'.format(n, scores))


shuffle과 random_stat매개변수를 조정한 교차 검증 테스트 점수

>> n_splits에 상관없이 결과가 유의미하다는 것을 확인할 수가 있음



'모델 평가와 성능 향상 > 교차 검증' 카테고리의 다른 글

다양한 교차 검증 방법  (0) 2018.04.03
cross-validation  (0) 2018.04.02

#!/usr/bin/env python3


cross-validation


0. 들어가기 전에

# library import

from sklearn.datasets import make_blobs

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import train_test_split


x, y = make_blobs(random_state=0)


x_train, x_test, y_train, y_test = \

  train_test_split(x, y,

                   random_state=0, test_size=0.3)


logreg = LogisticRegression().fit(x_train, y_train)

print('test score \n{:.3f}'.format(logreg.score(x_test, y_test))) # 0.900


데이터를 훈련 세트와 테스트 세트로 나누는 이유는  새로운 데이터에 모델이 얼마나 잘 일반화되는지 측정하기 위해서

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


cross-validation교차검증은 데이터를 여러 번 반복해서 나누고 여러 모델을 학습

보통 5 or 10을 사용


5-겹 교차 검증을 하려면 먼저 fold폴드라고 하는 비슷한 크기의 'subset'다섯 개로 나누고, 모델들을 만듬

첫 번째 모델은 첫 번째 fold를 테스트 세트로 사용하고 나머지 (2에서 5까지) fold를 훈련 세트로 사용하여 학습

즉 이 모델은 fold 2~5까지의 데이터를 사용해 만들어지고 fold1을 사용해 정확도를 평가함


그 다음 두 번째 모델은 fold2를 테스트 세트로 사용하고 fold1, 3 ,4, 5의 데이터를 훈련 데이터로 사용

이런 방법으로 3, 4, 5를 테스트 세트로 사용해 반복

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


# library import

import mglearn

import matplotlib.pyplot as plt


mglearn.plots.plot_cross_validation()

plt.show()

5-겹 교차 검증에서의 데이터 분할


+ Recent posts