Python/ML & DL 공부

[ML] 05-2 교차 검증과 그리드 서치

dori_0 2022. 3. 11. 16:21

혼자 공부하는 머신러닝+딥러닝 책을 바탕으로 공부한 내용입니다.

 

CH5 트리 알고리즘 ②

최적의 모델을 위한 하이퍼파라미터 탐색

 


 

검증 세트, 교차 검증에 대해 배우기
그리드 서치와 랜덤 서치를 이용해 최적의 성능을 내는 하이퍼파라미터를 찾아보자

 

 

▶ 검증 세트

  • 검증세트는 하이퍼파라미터 튜닝을 위해 모델을 평가할 때, test set을 사용하지 않기 위해 train set에서 다시 떼어 낸 data set이다.

 

test set으로 일반화 성능을 올바르게 예측하려면 가능한 한 test set을 사용하지 않아야 한다.

test set을 사용하지 않고 모델이 과대적합인지 과소적합인지 판단하기 위해 검증 세트를 이용하자

 

 

  1. train set에서 모델을 훈련하고 검증 세트로 모델 평가
  2. 테스트하고 싶은 매개변수를 바꿔가며 가장 좋은 모델 찾기
  3. 이 매개변수를 사용해 train set, 검증 세트를 합쳐 전체 훈련 데이터에서 모델을 다시 훈련
  4. 마지막으로 test set에서 최종 점수 평가

 

데이터를 불러와 직접 실습해보자

import pandas as pd
wine = pd.read_csv("https://bit.ly/wine_csv_data")
wine.head()

 

train_test_split() 함수를 2번 적용해 훈련 세트와 검증 세트로 나눠주고 크기를 확인해보자

# train set, test set으로 나누기
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(
    data, target, test_size=0.2, random_state=42)

# 검증 set 만들기
sub_input, val_input, sub_target, val_target = train_test_split(
    train_input, train_target, test_size=0.2, random_state=42)

# 크기 확인
print(sub_input.shape, val_input.shape)  #(4157, 3) (1040, 3)
  • 5,197개였던 훈련 세트가 4,147개가 되고, 검증 세트는 1,040개가 된 것이 확인된다.

 

이제 결정 트리 모델을 만들고 평가해보자

# 결정 트리 모델
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(sub_input, sub_target)
print(dt.score(sub_input, sub_target))
print(dt.score(val_input, val_target))

  • train set에 과대적합되어 있는 것으로 확인되므로 매개변수를 바꿔 더 좋은 모델을 찾아야 한다.

 

 

▶ 교차 검증

  • 훈련 세트를 여러 폴드로 나눈 다음 한 폴드가 검증 세트의 역할을 하고 나머지 폴드에서는 모델을 훈련
  • 교차 검증은 이런 식으로 모든 폴드에 대해 검증 점수를 얻어 평균하는 방법

 

사이킷런에는 cross_validate()라는 교차 검증 함수가 있다.

직접 검증 세트를 떼어 내지 않고 train set 전체를 이 함수에 전달해보자

# 교차 검증 함수 사용
from sklearn.model_selection import cross_validate
scores = cross_validate(dt, train_input, train_target)
print(scores)

  • 처음 2개의 키는 모델을 훈련하는 시간, 검증하는 시간을 의미
  • 교차 검증의 최종 점수는 test_score 키에 담긴 5개의 점수를 평균하여 얻음
# 교차 검증의 점수
import numpy as np
print(np.mean(scores['test_score']))  #0.855300214703487

 

cross_validate()는 훈련 세트를 섞어 폴드를 나누지 않으므로

교차 검증을 할 때 훈련 세트를 섞으려면 분할기를 지정해야 한다.

 

  • 회귀 모델일 경우 - KFold 분할기 사용
  • 분류 모델인 경우 - StratifiedKFole 사용

 

 

위에서 수행했던 교차 검증은 다음 코드와 동일하다

# 위와 같은 식
from sklearn.model_selection import StratifiedKFold
scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
print(np.mean(scores['test_score']))  #0.855300214703487

# 10-폴드 교차 검증 수행
splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=splitter)
print(np.mean(scores['test_score']))  #0.8574181117533719
  • n_splits 매개변수는 몇(k) 폴드 교차 검증을 할지 정한다.
  • 우리는 10-폴드 교차 검증을 수행해보았다.

 

 

이제 결정 트리의 매개변수 값을 바꿔가며 가장 좋은 성능이 나오는 모델을 찾아보자

이때, test set을 사용하지 않고 교차 검증을 통해 좋은 모델을 고를 것이다.

 

 

 

▶ 하이퍼파라미터 튜닝

  • 모델 파라미터 - 머신러닝 모델이 학습하는 파라미터
  • 하이퍼파라미터 - 모델이 학습할 수 없어서 사용자가 지정해야 하는 파라미터
  • 그리드 서치 
    • 하이퍼파라미터 탐색을 자동화 해주는 도구
    • 탐색할 매개변수를 나열하면 교차 검증을 수행하여 가장 좋은 검증 점수의 매개변수 조합을 선택
    • 이 매개변수의 조합으로 최종 모델 훈련
    • 별도로 cross_validate() 함수를 호출할 필요가 없음

 

 

사이킷런의 그리드 서치를 어떻게 사용하는지 간단한 예로 확인해보자

# 예시 - min_impurity_decrease 매개변수의 최적값 찾아보기
from sklearn.model_selection import GridSearchCV
params = {'min_impurity_decrease' : [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}

# 그리드 서치 객체 만들기
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)

gs.fit(train_input, train_target)

  • GridSearchCV의 cv 매개변수 기본값은 5이므로 여기서는 5*5 = 25개의 모델을 훈련함
  • n_jobs=-1로 지정하면 시스템에 있는 모든 코어를 사용한다.

 

 

사이킷런의 그리드 서치는 훈련이 끝나면 25개의 모델 중 검증 점수가

가장 높은 모델의 매개변수 조합으로 전체 훈련 세트에서 자동으로 모델을 다시 훈련한다.

( 이 모델은 gs 객체의 best_estimator_ 속성에 저장 되어 있음 )

dt = gs.best_estimator_
print(dt.score(train_input, train_target))

# 최적의 매개변수
print(gs.best_params_)

  • best_params_로 최적의 매개변수 찾기
  • 0.0001이 가장 좋은 값으로 선택되었다.

 

# 교차 검증의 평균 점수
print(gs.cv_results_['mean_test_score'])

# 가장 큰 값의 인덱스 추출
best_index = np.argmax(gs.cv_results_['mean_test_score'])
print(gs.cv_results_['params'][best_index])

  • 교차 검증 점수와 가장 큰 값의 인덱스를 다음과 같이 구할 수 있다.
  • 넘파이 argmax() 함수를 사용하여 가장 큰 값의 인덱스 추출

 

 

 

결정 트리에서 min_impurity_decrease는 노드를 분할하기 위한 불순도 감소 최소량을 지정한다.

이번에는 이것과 더불어 max_depth, min_samples_split로 노드를 나누기 위한 최소 샘플 수도 골라보자

# 조금 더 복잡한 매개변수 조합 탐색
params = {'min_impurity_decrease': np.arange(0.0001, 0.001, 0.0001),
         'max_depth': range(5, 20, 1),
         'min_samples_split': range(2, 100, 10)}
         
# 그리드 서치 실행
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
gs.fit(train_input, train_target)

# 최상의 조합 확인
print(gs.best_params_)
# 최상의 교차 검증 점수 확인
print(np.max(gs.cv_results_['mean_test_score']))

  • 매개변수로 수행할 교차 검증 횟수는 9*15*10 = 1350개이다.
  • 기본 5-폴드 교차 검증을 수행하므로 만들어지는 모델의 수는 6750개

 

 

GridSearchCV 클래스를 사용하면 일일이 바꿔가며 교차 검증을 수행하지 않고

원하는 매개변수 값을 나열하면 자동으로 교차 검증을 수행해 최상의 매개변수를 찾을 수 있다.

 

 

 

▶ 랜덤 서치

이번에는 랜덤 서치를 사용해 매개변수 값의 목록을 전달하는 것이 아닌

매개변수를 샘플링할 수 있는 확률 분포 객체를 전달해보자

 

 

[ randint, uniform 사용 예시 ]

from scipy.stats import uniform, randint

# randint 객체에서 10개 숫자 샘플링
rgen = randint(0, 10)
rgen.rvs(10)  #array([6, 5, 2, 1, 5, 1, 6, 2, 4, 8])
np.unique(rgen.rvs(1000), return_counts=True)

# uniform 클래스 사용법도 동일
ugen = uniform(0, 1)
ugen.rvs(10)

  • randint, uniform 클래스는 균등 분포에서 샘플링을 한다.
  • randint는 정숫값을 뽑고 uniform은 실숫값을 뽑는다.

 

 

앞에서는 직접 매개변수 값의 목록을 지정했었는데 이번에는 랜덤 서치를 사용해보자

params = {'min_impurity_decrease': uniform(0.0001, 0.001),
         'max_depth': randint(20, 50),
         'min_samples_split': randint(2, 25),
         'min_samples_leaf': randint(1, 25)}

from sklearn.model_selection import RandomizedSearchCV
gs = RandomizedSearchCV(DecisionTreeClassifier(random_state=42), params,
                       n_iter=100, n_jobs=-1, random_state=42)
gs.fit(train_input, train_target)
  • min_samples_leaf 매개변수는 리프 노드가 되기 위한 최소 샘플의 개수
  • n_iter 매개변수는 샘플링의 횟수로 총 100번 샘플링하도록 지정하였다.

 

 

이제 최적의 매개변수 조합과 교차 검증 점수를 출력해보자

# 최적의 매개변수 조합 출력
print(gs.best_params_)
# 최고의 교차 검증 점수 출력
print(np.max(gs.cv_results_['mean_test_score']))

 

최적의 모델은 이미 전체 train set으로 훈련되어 best_estimator_ 속성에 저장되어 있다.

이 모델을 최종 모델로 결정하고 test set의 성능을 확인해보자

dt = gs.best_estimator_
print(dt.score(test_input, test_target))  #0.86

 

 

 

▶ 정리

  1. 교차 검증을 사용해 다양한 하이퍼파라미터를 탐색
  2. 테스트하고 싶은 매개변수 리스트를 만들어 이 과정을 자동화하는 그리드 서치를 사용하면 편리함
  3. 랜덤 서치는 연속된 매개변수 값을 탐색할 때 유용
    • 탐색 값을 샘플링 할 수 있는 확률 분포 객체를 전달

 

'Python > ML & DL 공부' 카테고리의 다른 글

[ML] 06-1 군집 알고리즘  (0) 2022.03.12
[ML] 05-3 트리의 앙상블  (0) 2022.03.11
[ML] 05-1 결정 트리  (0) 2022.03.11
[ML] 04-2 확률적 경사 하강법  (0) 2022.03.10
[ML] 04-1 로지스틱 회귀  (0) 2022.03.07