AI/혼자공부하는머신러닝딥러닝

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

inthyes 2024. 1. 22. 17:28

검증 세트

검증 세트 : 하이퍼파라미터 튜닝을 위해 모델을 평가할 때, 테스트 세트를 사용하지 않기 위해 훈련 세트에서 다시 떼어 낸 데이터 세트

 

훈련 세트에서 모델을 훈련하고 검증 세트로 모델을 평가한다.

테스트하고 싶은 매개변수를 바꿔가며 가장 좋은 모델을 고르고 매개변수를 사용해 훈련, 검증 세트를 합쳐 훈련 데이터에서 모델을 다시 훈련한다. 

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

 

class 열을 타깃으로 사용하고 나머지는 특성 배열에 저장한다.

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)

 

train_input, train_target을 다시 train_test_split() 함수에 넣어 훈련 세트와 검증 세트를 생성한다. 이때 test_size를 지정하여 train_input의 약 20%를 val_input으로 생성한다.

sub_input, val_input, sub_target, val_target = train_test_split(train_input, train_target, test_size = 0.2, random_state = 42)

 

훈련 세트와 검증세트의 크기를 출력하여 검증세트가 1040개로 분리되었음을 확인할 수 있다.

print(sub_input.shape, val_input.shape)

 

결정 트리 모델을 만들고 평가를 진행해본 결과 아래 결과값과 같이 과대 적합되어 있음을 확인할 수 있다.

from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier()
dt.fit(sub_input, sub_target)
print(dt.score(sub_input, sub_target))
print(dt.score(val_input, val_target))

교차 검증

교차 검증 : 훈련 세트를 여러 폴드로 나눈 다음 한 폴드가 검증 세트의 역할을 하고 나머지 폴드에서 모델을 훈련하는 것

교차검증은 모든 폴드에 대해 검증 점수를 얻어 평균을 구한다.

 

사이킷런의 cross_validate()를 활용하여 교차 검증함수를 출력한다.

from sklearn.model_selection import cross_validate
scores = cross_validate(dt, train_input, train_target)
print(scores)

 

 

교차 검증의 최종 점수는 test_score 키에 담긴 5개의 점수를 평균하여 얻을 수 있다.

이 때 test_score은 검증 폴드의 점수를 의미한다.

import numpy as np
print(np.mean(scores['test_score']))

 

교차 검증을 수행할 때 훈련 세트를 섞기 위해서는 분할기를 지정해야한다.

사이킷런의 분할기는 교차 검증에서 폴드를 어떻게 나눌지 결정해주는 역할을 한다.

 

아래와 같은 코드를 수행하면 위의 출력과 동일한 값이 출력된다.

from sklearn.model_selection import StratifiedKFold
scores = cross_validate(dt, train_input, train_target, cv = StratifiedKFold())
print(np.mean(scores['test_score']))

 

훈련 세트를 섞은 후 10-폴드 교차 검증을 수행하려면 아래와 같이 코드를 작성해야한다.

n_splits 매개변수는 몇(k)폴드 교차 검증을 수행할지 정하는 역할을 한다.

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']))

하이퍼파라미터 튜닝

그리드 서치는 하이퍼파라미터 탐색을 자동화해주는 도구이다. 탐색할 매개변수를 나열하면 교차 검증을 수행하여 가장 좋은 검증 점수의 매개변수 조합을 선택한다. 이 후 이 매개변수 조합으로 최종 모델을 훈련한다.

사이킷런의 GridSearchCV 클래스는 하이퍼파라미터 탐색과 교차 검증을 한 번에 수행한다.

 

기본 매개변수를 사용한 결정 트리 모델에서 min_impourity_decrease 매개변수의 최적값을 찾는 코드를 구현한다.

가장 먼저 클래스를 임포트하고 탐색할 매개변수와 탐색할 값의 리스트를 딕셔너리로 생성한다.

from sklearn.model_selection import GridSearchCV
params = {'min_impurity_decrease' : [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}

 

GridSearchCV클래스에 탐색 대상 모델과 params 변수를 전달하여 그리드 서치 객체를 생성한다.

gs = GridSearchCV(DecisionTreeClassifier(random_state = 42), params, n_jobs = -1)

 

GridSearchCV의 cv 매개변수 기본값은 5이기 때문에 min_impurity_decrease값마다 5-폴드 교차 검증을 수행한다.

즉 5 * 5인 25개의 모델을 훈련하는 것이다.

 

 

gs.fit(train_input, train_target)

 

gs객체의 best_estimator_속성에 검증 점수가 가장 높은 모델의 매개변수 조합으로 다시 훈련된 모델이 삽입되어 있다.

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

 

최적의 매개변수는 best_params_ 속성에 저장되어 있다.

print(gs.best_params_)

 

각 매개변수에서 수행한 교차 검증의 평균 점수는 cv_results_속성의 'mean_test_score'키에 저장되어 있다.

print(gs.cv_results_['mean_test_score'])

 

넘파이 argmax()함수를 사용하면 평균 점수 중 가장 큰 인덱스 추출이 가능하다.

best_index = np.argmax(gs.cv_results_['mean_test_score'])
print(gs.cv_results_['params'][best_index])

 

 

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)}

 

min_impurity_decrease는 0.0001에서 0.001이 될 때 까지 0.0001씩 증가하는 것이기에 배열의 원소는 총 9개이다.

max_depth는 5에서 20이 될 때까지 1씩 증가하니 때문에 10개의 값을 생성한다.

min_samples_split는 2에서 100까지 10씩 증가하면서 10개의 값을 만든다.

 

결과적으로 매개변수로 수행할 교차 검증 횟수는 9 * 15 * 10 = 1350개이다.

 

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']))

 

랜덤서치

랜덤서치는 연속된 매개변수 값을 탐색할 때 유용하다. 탐색할 값을 직접 나열하는 것이 아니고 탐색 값을 샘플링할 수 있는 확률 분포 객체를 전달한다. 지정된 횟수만큼 샘플링하여 교차 검증을 수행하기 때문에 시스템 자원이 허락하는 만큼 탐색량을 조절할 수 있다.

 

싸이파이의 stats 서브 패키지에 있는 uniform은 실수값을, randint는 정수값을 뽑아 균등 분포에서 샘플링이 가능하도록 한다.

from scipy.stats import uniform, randint

 

rgen = randint(0, 10)
rgen.rvs(10)

 

np.unique(rgen.rvs(1000), return_counts = True)

 

ugen = uniform(0, 1)
ugen.rvs(10)

 

min_samples_leaf 매개변수는 리프 노드가 되기 위한 최소 샘플의 개수를 지정한다.

이 매개변수를 포함하여 탐색할 매개변수의 딕셔너리를 새로 구현한다.

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),}

 

위 params에 정의된 매개변수 범위에서 총 100번(n_iter 매개변수)을 샘플링하여 교차 검증을 수행하고 최적의 매개변수 조합을 찾는다.

최적의 매개변수 조합을 출력한다.

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)

print(gs.best_params_)

 

최괴의 교차 검증 점수를 출력한다.

print(np.max(gs.cv_results_['mean_test_score']))

 

최적의 모델은 이미 전체 훈련 세트로 훈련되어 best_estimator_ 속성에 저장되어 있다. 이 모델을 최종 모델로 결정하고 테스트 세트의 성능을 출력한다.

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

 

'AI > 혼자공부하는머신러닝딥러닝' 카테고리의 다른 글

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