Machine Learning/[Kaggle Course] ML (+ 딥러닝, 컴퓨터비전)

[Kaggle Course] Cross-Validation(교차검증)

WakaraNai 2020. 10. 23. 13:13
728x90
반응형

Introduction

지금까지 validation(검증)(or holdout) data set을 사용하여 model을 quality(품질)을 측정했습니다.

그러나 이같은 접근 방식에는 몇가지 단점이 존재합니다. 

예로 5000개의 행(row)가 있는 data set이 있다고 가정해봅시다.

일반적으로 데이터의 약 20%을, 또는 1000개의 행을 validation data set으로 둡니다.

이는 모델의 점수(MAE가 낮은지 확인하기)를 결정할 때 운이 따릅니다.(it leaves some random chance)

즉, 모델이 1000개의 행 중 한 집합에서 잘 수행될 수 있지만 다른 1000개의 행에서는 정확하지 않을 수 있죠.

 

극단적인 경우를 가정한다면, validation set에 데이터가 오로지 1 row만 있는 것입니다.

대체가능한 모델(alternative model)과 비교하는 경우,

단일 데이터 지점에서 가장 잘 예측하는 모형의 대부분의 운에 따를 수 밖에 없죠.

 

일반적으로 validation set가 클수록 model quality의 측정값에서

randomness( aka "noise")이 감소하고 신뢰성이 높아집니다.

그런데 말이죠, train data에서 행을 제거해야만 더 큰 대규모의 validation set을 얻을 수 있으므로,

train set가 작다는 것은 더 나쁜 모델을 의미합니다!

진퇴양난이 따로 없습니다.

 

 

What is Cross-Validation?

교차 검증에서는 여러 가지 model quality에 대한 측정값을 얻기 위해

데이터의 여러 하위 집합(subsets)에서 모형화 프로세스(modeling process)를 실행합니다. 

 

예를 들어, 전체 data set에서 20% 분리하여 5조각으로 나눈 뒤, 각 조각을 5개의 "fold(배수)"라고 부릅니다.

그 다음엔, 각 fold에 대해 실험을 하는 거죠.

  • 첫번째 실험에서, 1st fold를 validation set (or holdout)으로 두고 다른 data는 training data로 둡니다. 이는 20%의 holdout set을 기반한 model quality의 측정값을 돌려주겠죠.
  • 두번째 실험에서, 2nd fold부터 hold out 합니다. (당연히 2nd fold 외 data는 model을 train하는데 쓰입니다) 이 holdout set은 이후에 또다른 두번째 model quality 측정값을 내놓겠죠
  • 이러한 과정을 반복합니다. 각 fold를 holdout set(validation)으로 두고 실행해보는 거죠. 그럼 전체 데이터가 한번쯤은 holdout set이 될테며, 모든 행을 동시에 사용하지 않지만 모든 행을 기반으로 한 model quality의 측정도를 얻게 됩니다.

 

When should you use cross-validation?

각 fold 별로 validation set을 정해서 전체 data에 대해 해본다는 건 시간이 오래 걸리는 일이긴 합니다.

그렇다면 언제 사용해야 좋을까요?

 

컴퓨터에 무리가지 않는 소규모 data set에서는 대단히 좋습니다. 

이 때는 굳이 train set과 valid set을 구분하여 그 과정을 추적하지 않고

바로 cross-validation을 사용하는 것이 효율적입니다.

 

대규모의 data set의 경우, 하나의 validation set으로 충분합니다. 코드는 더 빨리 실행되며, 데이터 용량은 충분하므로 일부 코드를 hold out 해둔 뒤 다시 사용할 필요는 없습니다.

대규모와 소규모를 구분짓는 단순한 임계값은 없습니다.

그러나 model 실행에 몇 분 또는 그 이하로 소요되면 cross-validation으로 전환할 가치가 있습니다.

 

 

또는 cross-validation을 실행하여 각 실험의 score가 점수에 근접한지 확인할 수 있습니다.

각 실험에서 동일한 결과를 얻을 경우, 하나의 validation set으로 충분하겠지요?

 

 

 

Example

시작 전에 작업 좀 미리 해두겠습니다.

missing values를 imputer로 채워주는 pipeline을 정의하고 random forest 모델로 예측을 해볼게요.

pipeline 없이 cross-validation이 가는하지만, 그건 좀 어렵습니다!

pipeline을 사용하여 code를 놀랍도록 깔끔하게 만들어봅시다.

 

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer

my_pipeline = Pipeline(steps=[('preprocessor', SimpleImputer()),
                              ('model', RandomForestRegressor(n_estimators=50, random_state=0))])

- n_estimators: the number of trees in the forest

 

cross_val_score()

이 함수는 scikit-learn 모듈 속에 있으며 cross-validation scores를 반환해주는 함수입니다.

  • "cv" parameter: fold의 수를 정합니다.
  • "scoring" parameter:  model quality의 측정해주는 방법(측정 도구)의 이름을 적습니다. 아래 예시는 negative MAE를 선택했습니다.
    • negative MAE란 그저 "-1"을 곱해준 것 뿐이예요
from sklearn.model_selection import cross_val_score

# Multiply by -1 since sklearn calculates *negative* MAE
scores = -1 * cross_val_score(my_pipeline, X, y,
                              cv=5,
                              scoring='neg_mean_absolute_error')

print("MAE scores:\n", scores)

위와 같이 scores를 print해보면 각 fold 별로 MAE를 산출한 결과를 리스트 형식으로 출력합니다.

 

negative MAE로 해보니 조금 다르죠? Scikit-learn은 모든 행렬에 대해 정의되어 있으므로 수가 클 수록 좋습니다. 

negative MAE는 다른 곳에서 들어본 적은 없을 테지만, 이 대회에서만 일관성을 유지해주네요.

 

보통 다른 model들과 비교하여 단 하나의 model quality 측정값을 원하죠. 그래서 위의 결과의 평균을 내봤습니다.

print("Average MAE score (across experiments):")
print(scores.mean())

 

 

 

 

Exercise

 

Step 1. Write a useful function

  • using the data in X and Y to create folds
  • SimpleImputer() to replace missing values, and
  • RandomForestRegressor() to fit random forest model
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer

def get_score(n_estimators):
    my_pipeline = Pipeline(steps =[('preprocessor',SimpleImputer()),
                                 ('model',RandomForestRegressor(n_estimators=n_estimators, random_state=0))])
    scores = -1 * cross_val_score(my_pipeline,X,y,
                                 cv=3,
                                 scoring='neg_mean_absolute_error')
    return scores.mean()

 

Step 2. Test different parameter values

get score의 parameter는 n_estimators.

즉, RandomForest model 속 tree의 수이다.

tree의 수에 따라 어떻게 달라지는 result라는 딕셔너리에 저장해보자.

result[i]가 get_score(i)의 평균 MAE값을 담고 있도록.

 

#Way1
numTrees=[50*i for i in range(1,9)]

results = {numTree : get_score(numTree) for numTree in numTrees}
#Way2
results = {}
for i in range(1,9):
    results[50*i] = get_score(50*i)

 

 

Step 3. Find the best parameter value

Step2를 시각화해주는 코드입니다. 한 번 써보세요.

import matplotlib.pyplot as plt
%matplotlib inline

plt.plot(list(results.keys()), list(results.values()))
plt.show()

가장 낮은 값을 산출하는 n_estimator가 어디인지 찾아보세요. 그게 바로 best_n_estimators랍니다.

해당 n_estimator로 get_score()를 하면 됩니다!

 

 

 

+) 추가적으로 공부하고 싶다면 "Hyperparameter optimization"에 대해서 알아보세요. "grid search"쪽으로 시작해보시고

728x90
반응형