본문 바로가기

Computer Science/Machine Learning

Learning Curves

Learning Curves는 우리가 만든 모델의 성능을 조사하기에 가장 좋은 방법입니다. 머신러닝에서 우리는 끊임없이 underfitting과 overfitting 사이의 어딘가 적정한 지점을 찾기 위해 노력합니다. 우리가 조금 결함이 있는 모델을 만들어 냈다면, 어떤 부분에서 잘못되었는지, 그래서 어디를 고쳐야 하는지를 아는 것은 아주 중요합니다. 예를 들면, 약간 underfitting된 상태라면 새로운 데이터를 얻어오는 것이 도움이 될것이고, overfitting된 상태라면 hyper-parameter를 수정하는 것이 도움이 될 것입니다. 아니면 새 데이터를 더 수집할 수도 있겠지요. 이번 포스팅의 목적은 예측기의 성능이 데이터의 수에 따라 어떻게 바뀌는지 알아보는 것입니다. 나아가 내 예측기가 충분하다고 생각하더라도 이제 진짜 최적의 상태인지 아니면 더 나아질 여지가 있는지 알아볼 수도 있겠지요.

 

Learning Curves를 만드는 것은 Scikit learn 라이브러리에 이미 함수가 제공되어 있어 간단합니다. 

 

 

import matplotlib.pyplot as plt
import numpy as np

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

from sklearn.model_selection import train_test_split
from sklearn.model_selection import learning_curve

X, y = load_breast_cancer(return_X_y=True)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size = 0.1, random_state = 12)

clf = DecisionTreeClassifier(max_depth=3)
n_folds = 5
train_sizes = np.linspace(0.1, 1.0, 6)

 

 

이전 포스팅과 같은 Breast Cancer 데이터 셋을 사용해서, train과 test 데이터를 split 하는 부분 까지는 동일하게 진행합니다. 그리고 max_depth=3의 인자도 정해주었고요.

그리고 우리는 이전 포스팅과 같은 5-fold CV를 사용하고자 합니다. 그리고 learning curve에 들어갈 training size를 10%부터  100%까지 다르게 넣어줄 것이기 때문에 그 정도를 쪼개는 변수 train_sizes를 추가했습니다. 0.1부터 1.0까지 6개의 부분으로 쪼개집니다.

 

 

train_sizes, train_scores, test_scores, fit_times, _ =\
    learning_curve(clf, X_train, y_train,
                   cv=n_folds, train_sizes=train_sizes,
                   scoring = 'accuracy',
                   return_times=True)

 

 

이제 가장 중요한 함수를 호출할 차례입니다. 사용될 train size와 train score, test score을 넣어주고, fit times를 써주는데, 이 뜻은 우리가 이 모델을 훈련시키는데 걸리는 시간을 설정해주는 것입니다. 일반적으로 중요하지 않지만 뉴런 네트워크 같이 아주 많은 데이터를 다룰 때는 설정해주기도 합니다.  그리고 그 변수들을 =\ 빈 값으로 설정합니다.

그리고 learning curve 함수를 호출해서, 의사결정나무, train 데이터를 parameter로 넣어주고, cross validation을 위한 값, train size, scoring, 그리고 return time=True로 설정해서 반환받습니다.

*정확도랑은 상관없지만 우리는 training time도 plot하고자 합니다. 더 큰 데이터 셋일 수록 중요해지는 값이기 때문입니다. 결과는 numpy 배열로 받는데, row는 training data set의 fraction에 따라, column은 5-fold CV의 fold에 따라 달라집니다. 

 

 

train_scores 출력결과

* 10%부터 100%까지 6개의 배열로 나눴기 때문에 행이 6개

* 1~5 fold 에 따라 달라지는 score이 열별로 나와있음

 

 

train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
fit_times_mean = np.mean(fit_times, axis=1)
fit_times_std = np.std(fit_times, axis=1)

 

 

1행 : Score 평균 for all the cross validation on train data

2행 : Score 표준편차 for all the cross validation on train data

3행 : Score 평균 for all the cross validation on test data

4행 : Score 표준편차 for all the cross validation on test data

5행 : Time 평균 for all the cross validation

6행 : Time 표준편차 for all the cross validation

 

 

_, axes = plt.subplots(1, 2, figsize=(20, 5))
axes[0].grid()
axes[0].fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1,
color="r")
axes[0].fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1,
color="g")
axes[0].plot(train_sizes, train_scores_mean, 'o-', color="r",
label="Training score")
axes[0].plot(train_sizes, test_scores_mean, 'o-', color="g",
label="Cross-validation score")
axes[0].legend(loc="best")
axes[0].set_xlabel("Training examples")
axes[0].set_ylabel("accuracy")
axes[0].set_title("Data sensitivity")
axes[1].grid()
axes[1].plot(train_sizes, fit_times_mean, 'o-')
axes[1].fill_between(train_sizes, fit_times_mean - fit_times_std,
fit_times_mean + fit_times_std, alpha=0.1)
axes[1].set_xlabel("Training examples")
axes[1].set_ylabel("fit_times")
axes[1].set_title("Scalability of the model")

 

 

Plot해보면 결과는 아래와 같습니다.

 

 

 

 

왼쪽 그래프의 경우 x축은 사용된 training data 수, y축은 정확도입니다. 정확도는 training의 데이터의 경우 데이터가 늘수록 낮아지고, 반대로 CV의 점수는 올라갑니다. 두 점수 모두 어느정도 수렴하는 양상을 보이지만 둘 사이의 차이는 꽤 나는 편입니다. 즉 우리가 데이터를 더 추가할 수록 둘의 경향은 더 가까워질 것이고, 따라서 더 높은 정확도를 원한다면 더 많은 데이터가 도움이 될 것입니다. 다른 방안으로는 random forest나 resulting curves같은 다른 classifier를 사용하는 것 정도가 있겠습니다.

 

오른쪽 그래프의 경우 example의 수를 높일 수록 시간이 어떻게 바뀌는 지를 나타냅니다. 증가하는 양상을 보이지만 그렇게 급격해보이지 않고, 하지만 이 그래프는 데이터의 수가 많아질 수록 시간이 오래 걸린다는 부분은 명확히 보여줍니다. 사용된 데이터는 400개 뿐이기 때문입니다.

 

추후 수정