Cross validation, Grid Search

홍정완·2021년 11월 26일
0

Machine Learning

목록 보기
3/3
post-thumbnail
검증 세트가 필요한 이유 이해 및 교차 검증 학습, 그리드 서치와 랜덤 서치를 이용해 최적의 성능을 내는 하이퍼 파라미터를 찾는다.

이전까지는 문제를 간단히 하려고 테스트 세트를 사용했다.

하지만 테스트 세트로 일반화 성능을 올바르게 예측하려면 가능한 한 테스트 세트를 사용하면 안 된다.


모델을 만들고 나서 마지막에 딱 한 번만 사용하는 것이 좋다.



검증 세트


import pandas as pd

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

우선 pandas로 CSV 데이터를 읽는다.

👇


data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

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

👇


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)

훈련 세트와 테스트 세트 나눈다.

👇


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

train_input과 trian_target을 다시 train_test_split() 함수에 넣어 훈련 세트 sub_input, sub_target과 검증 세트 val_input, val_target을 만든다. 여기에서도 test_size 매개변수를 0.2로 지정하여 train_input의 약 20%를 val_input으로 만든다.

👇


단순히 train_test_split() 함수를 2번 적용해서 훈련 세트와 검증 세트로 나눈 것.


print(sub_input.shape, val_input.shape)
(4157, 3) (1040, 3)

훈련 세트 5,197 👉 4,157
검증 세트 1,040


지금 만든 검증 세트를 이용해서 모델을 평가하면 훈련 세트에 과대적합.
매개변수를 바꿔서 더 좋은 모델을 찾아야한다.



교차 검증


교차 검증을 이용하면 안정적인 검증 점수를 얻고 훈련에 더 많은 데이터 사용 가능하다.

5-폴드 교차 검증이나 10-폴드 교차 검증을 사용하면 80~90%까지 훈련에 사용할 수 있다.
검증 세트가 줄어들지만 각 폴드에서 계산한 검증 점수를 평균하기 때문에 안정된 점수로 생각할 수 있다.


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


출력 값 : {'fit_time': array([0.00693846, 0.00677943, 0.00702143, 0.00693512, 0.006706  ]), 'score_time': array([0.00042367, 0.00040078, 0.00040078, 0.00040293, 0.00040627]), 'test_score': array([0.86923077, 0.84615385, 0.87680462, 0.84889317, 0.83541867])}

사이킷런에는 cross_validate() 교차 검증 함수가 있다.
이 함수는 fit_time, score_time, test_score 키를 가진 딕셔너리 반환한다.

기본적으로 5-폴드 교차 검증을 수행, cv 매개변수에서 폴드 수를 바꿀 수도 있다.


import numpy as np

print(np.mean(scores['test_score']))
0.855300214703487

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

👇👆


from sklearn.model_selection import StratifiedKFold

scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
print(np.mean(scores['test_score']))
0.855300214703487

앞서 수행한 교차 검증은 위 코드와 동일하다.

👇


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

10-폴드 교차 검증을 수행하려면 위 코드와 같이 작성한다.



하이퍼 파라미터 튜닝


머신러닝 모델이 학습하는 파라미터 👉 모델 파라미터
사용자가 지정해야되는 파라미터 👉 하이퍼 파라미터


사이킷런과 같은 머신러닝 라이브러리를 사용할 때 하이퍼파라미터는 모두 클래스나 메서드의 매개변수로 표현된다.


ex) max_depth의 최적값은 min_samples_split 매개변수의 값이 바뀌면 함께 달라진다.

최적값을 찾기위해 매개변수를 동시에 바꿔야한다. -> 매개변수가 많아지면 문제가 더 복잡해진다.


이런 문제를 그리드 서치를 통해 해결할 수 있다.

그리드 서치는 하이퍼 파라미터 탐색을 자동화해 주는 도구이다.



from sklearn.model_selection import GridSearchCV

params = {'min_impurity_decrease': [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}

우선 GridSearchCV 클래스를 임포트하고 탐색할 매개변수와 탐색할 값의 리스트를 딕셔너리로 만든다.

👇


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

결정 트리 클래스의 객체를 생성하자마자 바로 전달한다.

👇


gs.fit(train_input, train_target)

출력 값 : GridSearchCV(estimator=DecisionTreeClassifier(random_state=42), n_jobs=-1,
             param_grid={'min_impurity_decrease': [0.0001, 0.0002, 0.0003,
                                                   0.0004, 0.0005]})

gs 객체에 fit() 메서드 호출 -> 그리드 서치 객체는 결정 트리 모델 min_impurity_decrease 값을 바꿔가며 총 5번 실행한다.

GridSearchCV의 cv 매개변수 기본값은 5, 따라서 min_impurity_decrease 값마다 5-폴드 교차 검증을 수행한다. 즉, 5 * 5 = 25개의 모델을 훈련한다.

n_jobs = -1 이렇게 지정하면 시스템에 있는 모든 코어를 사용한다, 기본값은 1

👇


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

최적의 하이퍼 파라미터를 찾으면 전체 훈련 세트로 모델을 다시 만들어야 한다.
-> gs 객체의 bestestimator 속성에 저장되어 있다.
이 모델을 일반 결정 트리처럼 똑같이 사용할 수 있다.

👇


print(gs.best_params_)
{'min_impurity_decrease': 0.0001}

가장 좋은 값으로 0.0001 선택

👇


print(gs.cv_results_['mean_test_score'])
[0.86819297 0.86453617 0.86492226 0.86780891 0.86761605]

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

👇


best_index = np.argmax(gs.cv_results_['mean_test_score'])
print(gs.cv_results_['params'][best_index])
{'min_impurity_decrease': 0.0001}

넘파이 argmax() 함수를 사용해 가장 큰 값의 인덱스를 추출한다.
그 다음 인덱스를 사용해 params 키에 저장된 매개변수를 출력해 앞에서 출력한 gs.bestparams 와 동일한지 확인한다.



중간 정리

    1. 먼저 탐색할 매개변수를 지정한다.
    1. 훈련 세트에서 그리드 서치를 수행하여 최상의 평균 검증 점수가 나오는 매개변수 조합을 찾는다. 이 조합은 그리드 서치 객체에 저장된다.
    1. 그리드 서치는 최상의 매개변수에서 (교차 검증에 사용한 훈련 세트가 아니라) 전체 훈련 세트를 사용해 최종 모델을 훈련한다. 이 모델도 그리드 서치 객체에 저장된다.



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)

출력 값 : GridSearchCV(estimator=DecisionTreeClassifier(random_state=42), n_jobs=-1,
             param_grid={'max_depth': range(5, 20),
                         'min_impurity_decrease': array([0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007, 0.0008,
       0.0009]),
                         'min_samples_split': range(2, 100, 10)})

print(gs.best_params_)

출력 값 : {'max_depth': 14, 'min_impurity_decrease': 0.0004, 'min_samples_split': 12}

최상의 매개변수 조합 확인


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

최상의 교차 검증 점수 확인

GrideSearchCV 클래스를 사용하면 매개변수를 일일이 수정하며 교창 검증을 수행하지 않아도 된다. 매개변수 값을 나열하면 자동으로 교차 검증을 수행해서 최상의 매개변수를 찾을 수 있다.



랜덤 서치

매개변수의 값이 수치일 때 범위나 간격을 미리 정하기 어려울 때나 많은 매개변수 조건이 있어 그리드 서치 수행 시간이 오래 걸릴 때 랜덤 서치를 이용하면 좋다.

랜덤 서치는 매개변수 값의 목록을 전달하는 것이 아닌, 매개변수를 샘플링할 수 있는 확률 분포 객체를 전달한다.


from scipy.stats import uniform, randint

싸이파이에서 2개의 확률 분포 클래스를 임포트한다.

👇

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

출력 값 : array([9, 7, 4, 5, 4, 1, 2, 4, 7, 5])

rvs : 랜덤 표본 생성 메서드

👇

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

출력 값 : (array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
 array([103,  95,  86, 113, 112, 114, 107,  97, 100,  73]))

1,000개를 샘플링해서 각 숫자의 개수를 확인해본다.

👇

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

출력 값 : array([0.17412564, 0.73879901, 0.29949778, 0.57661224, 0.4059046 ,
       0.46901339, 0.81568111, 0.88052148, 0.07833779, 0.27553489])

uniform 클래스를 사용해 0~1 사이에서 10개의 실수를 추출한다.
샘플링 횟수는 시스템 자원이 허락하는 범위 내에서 최대한 크게 하는 것이 좋다.

👇

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

탐색할 매개변수의 딕셔너리를 만든다.

min_samples_leaf 매개변수를 탐색 대상에 추가한다.
min_samples_leaf 매개변수는 리프 노드가 되기 위한 최소 샘플의 개수이다.
어떤 노드가 분할하여 만들어질 자식 노드의 샘플 수가 이 값보다 작을 경우 분할하지 않는다.

👇

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)

위 params에 정의된 매개변수 범위에서 총 100번 (n_iter 매개변수)을 샘플링하여 교차 검증을 수행하고 최적의 매개변수 조합을 찾는다. 그러면 앞서한 그리드 서치보다 훨씬 교차 검증 수를 줄이면서 넓은 영역을 효과적으로 탐색할 수 있다.

👇

print(gs.best_params_)

최적의 매개변수 조합 출력

👇

dt = gs.best_estimator_

최고의 교차 검증 점수 확인

👇

print(dt.score(test_input, test_target))
0.86

테스트 세트 점수는 검증 세트에 대한 점수보다 조금 작은 것이 일반적이다.



정리


선별 작업 성능을 끌어올리기 위해 결정 트리의 다양한 하이퍼 파라미터를 시도해야 한다.
이런 과정에서 테스트 세트는 최종 모델을 선택할 때까지 사용하지 않고 다른 세트를 이용한다.
이를 검증 세트(개발 세트), 검증 세트는 훈련 세트 중 일부를 다시 덜어 내어 만든다.

검증 세트를 여러 번 반복하는 걸 교차 검증, 나누어진 훈련 세트 한 덩어리를 폴드라고 부른다.
한 폴드 씩 돌아가며 검증 세트의 역할 수행 -> 최종 검증 점수는 모든 폴드의 검증 점수를 평균으로 계산

교차 검증을 통해 다양한 하이퍼 파라미터를 탐색, 머신러닝 라이브러리에서는 매개변수를 바꾼다.
이 과정을 자동화하는 그리드 서치를 사용하면 편리하다.

매개변수 값이 수치형이고 특히 연속적인 실숫값이면, 싸이파이의 확률 분포 객체를 전달하여 특정 범위 내에서 지정된 횟수만큼 매개변수 후보 값을 샘플링하여 교차 검증 시도 가능하다.



키워드 핵심


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

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

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

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


skikit-learn


  • cross_validate()는 교차 검증을 수행하는 함수

첫 번째 매개변수에 교차 검증을 수행할 모델 객체를 전달
두 번째, 세 번째 매개변수에 특성과 타깃 데이터를 전달


  • GridSearchCV는 교차 검증으로 하이퍼 파라미터 탐색을 수행

  • RandomizedSearchCV는 교차 검증으로 랜덤 한 하이퍼 파라미터 탐색을 수행



profile
습관이 전부다.

0개의 댓글