<알고가야하는 키워드>
검증세트(Validation set): 테스트 세트만 가지고 성능평가를 하다보면, 점점 테스트 세트에 맞추어지게 되는 아이러니한현상이 발생함, 이를 예방하기 위해서 Trainset중 일부분을 떼어내서 검증세트로 사용한다. (Testset는 찐찐 시험용으로만 쓰는것) 보통 6:2:2로 train, validation, test 비율로 떼어놓기도 한다.
교차검증(cross validation): 검증세트를 골고루 떼어내어서 사용하는 방법 이다.(검증셋의 점수는 각 떼어낸 검증셋들의 평균을 의미한다.) 아래 그림을 보면 골고루 떼어낸다는 말이 이해가 될것이다.
K-Fold Cross Validate: 훈련세트를 몇부분으로 나누는지에 따라서 K가 결정 된다. 보통은 5,10겹으로 분할하여서 사용한다. K겹 교차검증 이라고도 한다.
분할기(Splitter): 교차검증을 할때 검증셋을 만들기전 훈련세트를 섞을때 사용한다.
하이퍼 파라미터: 모델이 자동으로 학습하는 파라미터를 모델 파라미터 라고 함, 반대로 사람이 직접 지정해야 하는 파라미터를 하이퍼 파라미터 라고 부른다.
AutoML: 사람의 개입 없이 하이퍼파라미터 튜닝을 자동으로 수행하는 기술을 의미
하이퍼 파리미터 탐색: 여러개의 파라미터들을 각각 조절해가며 최적의 조합을 찾는다.
그리드 서치(Grid Search): 사이킷런에서 제공하며, 하이퍼파라미터 탐색&교차검증을 한번에 제공 한다.
그리드 서치의 과정
1. 탐색할 매개변수를 지정
2. 훈련세트에서 그리드 서치를 수행, 최상의 검증점수가 나오는 하이퍼 파라미터 매개변수를 저장
3. 최상의 매개변수를 활용하여 전체 훈련세트(test Set 제외한 부분, 검증셋도 학습됨)를 훈련한다.
랜덤서치(random search): 그리드 서치처럼 구체적인 값을 정해서 넣기보다, 일정 범위내의 무작위로 숫자를 정하여 여러번 반복하여 찾는 방법(매개변수로 활용 가능한 확률 분포 객체를 전달, '균등분포에서 샘플링 한다'), 연속된 매개변수값을 탐색할때 유용
<내용 요약>
-다양한 하이퍼 파라미터를 시도해봐야지 성능을 높일수 있음
-이 과정에서 테스트셋을 반복적으로 활용해서 평가하다보면, 테스트셋에 맞춰서 모델이 개발됨
-테스트셋은 단 한번 마지막으로 사용됨을 유의하고, 검증셋을 학습셋에서 떼어내어 사용한다.(개발셋 이라고도 함)
-교차검증을 활용하여 여러겹의 검증을 함으로써 안정성을 확보할수 있다.
<유용한 코드 (이번 파트는 신기한 코드가 많음, 전체코드를 볼것)>
#%% 검증셋(validation set) 나누는법
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)
# 분류는 기본적으로 cv=StratifiedKFold()를 사용하여 타깃 클래스를 골고루 나눈다.
from sklearn.model_selection import StratifiedKFold
import numpy as np
scores = cross_validate(dt,train_input, train_target, cv=StratifiedKFold())
print(scores)
'''
{'fit_time': array([0.01050639, 0.00809813, 0.00607872, 0.00823736, 0.00609064]), 학습하는데 걸린 시간
'score_time': array([0.0005343 , 0.00364852, 0.00092983, 0.00197411, 0.00100565]), 검증셋 시험 기간
'test_score': array([0.86923077, 0.84615385, 0.87680462, 0.84889317, 0.83541867])} 검증셋 점수
'''
print(np.mean(scores['test_score'])) # 0.855300214703487, 5개의 검증셋의 점수 평균
#%% 훈련세트를 한번 섞고, KFold 교차 검증을 하고 싶다면 다음과 같이 작성 한다.
# n_splits는 몇겹의 kFold 검증을 할지 물어보는 것이다.
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']))
전체코드는 아래와 같다
#%% 데이터 준비
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
data = wine[['alcohol', 'sugar','pH']].to_numpy()
target = wine['class'].to_numpy()
#%% 검증셋(validation set) 나누는법
from sklearn.model_selection import train_test_split
# 1. 8:2로 train, test 분리
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2,random_state=42)
# 2. train을 다시 8:2로 분리
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) # 학습 데이터 (4157, 3)
print(val_input.shape) # 검증 데이터 (1040, 3)
print(test_input.shape) # 테스트 데이터 (1300, 3)
#%% 검증셋을 활용한 성능평가
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(sub_input, sub_target)
print(dt.score(sub_input, sub_target)) # 0.9971133028626413
print(dt.score(val_input, val_target)) # 0.864423076923077 과대적합 되어있음
# %% 교차검증 Cross Validation(K-Fold cross Validation): 검증셋을 매번 다른 부분을 사용하여, 그것들의 정확도 평균을 구한다.
from sklearn.model_selection import cross_validate
import numpy as np
dt = DecisionTreeClassifier(random_state=42)
scores = cross_validate(dt, train_input, train_target) # 학습하기 전의 모델을 넣기(기본 5-Fold 검증임)
print(scores)
print(np.mean(scores['test_score']), "폴드검증의 평균") # 0.855300214703487
'''
{'fit_time': array([0.01050639, 0.00809813, 0.00607872, 0.00823736, 0.00609064]), 학습하는데 걸린 시간
'score_time': array([0.0005343 , 0.00364852, 0.00092983, 0.00197411, 0.00100565]), 검증셋 시험 기간
'test_score': array([0.86923077, 0.84615385, 0.87680462, 0.84889317, 0.83541867])} 검증셋 점수
'''
# %% crossvalidate함수는 분류는 StratifiedKFold, 회귀는 KFOLD 분할기를 사용한다.
# 위의 셀과 같은 기능을 수행하는 것이다. cv=StratifiedKFold()만 추가했을뿐(적절히 클래스에 따른 분류를 함)
from sklearn.model_selection import StratifiedKFold
import numpy as np
scores = cross_validate(dt,train_input, train_target, cv=StratifiedKFold())
print(np.mean(scores['test_score'])) # 0.855300214703487
#%% 훈련세트를 한번 섞고, KFold 교차 검증을 하고 싶다면 다음과 같이 작성 한다.
# n_splits는 몇겹의 kFold 검증을 할지 물어보는 것이다.
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']))
#%% 그리드 서치를 활용하여, 하이퍼 파라미터 탐색과
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) # n_jobs는 사용할 CPU의 개수, -1이면 모든 cpu 사용, 또한 cv는 5-Kfold 검증을 사용한다.
gs.fit(train_input, train_target) # 전체 trainset 던져주면 알아서 검증셋 분할함, 5-Fold * 5개의 파라미터 변수 = 25개의 각기다른 모델을 만든다.
# 이후 점수가 가장 좋은 모델의 파라미터를 차용, 우수한 1개의 모델을 만들어서 반환한다.
#%% 그리드 서치를 활용한 최상의 매개변수 탐색
dt = gs.best_estimator_ # 최적의 하이퍼 파라미터를 적용하여, 결정트리 모델이 만들어 진다.
print(dt.score(train_input, train_target)) # 0.9615162593804117
print(gs.best_params_) # {'min_impurity_decrease': 0.0001} 0.0001이 가장 좋은 값으로 설정됨
print(gs.cv_results_['mean_test_score']) # 각 파라미터에서 교차검증을 수행하여 나온 5개의 평균값 [0.86819297 0.86453617 0.86492226 0.86780891 0.86761605]
best_index = np.argmax(gs.cv_results_['mean_test_score']) # np.argmax() 함수를 사용하면 가장 큰 값의 인덱스 번호를 추출할수 있다
print(gs.cv_results_['params'][best_index]) # {'min_impurity_decrease': 0.0001}
#%% 조금더 복잡한 매개변수 조합을 탐색해보자
params = {'min_impurity_decrease': np.arange(0.0001, 0.001, 0.0001),
'max_depth': np.arange(5,20,1),
'min_samples_split': np.arange(2,100,10)} # arange할때 두번째 매개변수는 안들어가는걸 알아두자
print(params)
# 그리드 서치 시작
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
gs.fit(train_input, train_target)
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
#%% 사이파이를 활용한 균등분포 선발하기
from scipy.stats import uniform, randint
rgen = randint(0,10)
rgen.rvs(10) # array([7, 0, 4, 1, 8, 2, 3, 6, 4, 0], dtype=int64), 매 실행시마다 다르게 나옴, 균등 확률분포를 따른다
print(np.unique(rgen.rvs(1000), return_counts=True))
# (array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64), --> 등장한 숫자들
# array([ 92, 103, 113, 109, 98, 107, 82, 98, 107, 91], dtype=int64)) --> 각 숫자들의 출현 빈도
ugen = uniform(0,1)
ugen.rvs(10) # array([0.39282719, 0.87861909, 0.15096738, 0.44438743, 0.16319571, 0.83247993, 0.90397023, 0.43672869, 0.15032974, 0.97619753])
#%% 실제 적용
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)
print(gs.best_params_)
'''
{'max_depth': 39, 'min_impurity_decrease': 0.00034102546602601173, 'min_samples_leaf': 7, 'min_samples_split': 13}
'''
print(np.max(gs.cv_results_['mean_test_score']))
dt = gs.best_estimator_
print(dt.score(test_input, test_target)) # 0.86
'머신러닝 & 딥러닝' 카테고리의 다른 글
[혼자 공부하는 머신러닝] 05-01 결정트리(Decision tree) (1) | 2024.02.06 |
---|---|
[혼자 공부하는 머신러닝] 04-02 확률적 경사하강법(SDGClassifier) (0) | 2024.02.03 |
[혼자 공부하는 머신러닝] 04-01 로지스틱 회귀 (0) | 2024.01.28 |
[혼자 공부하는 머신러닝] 03-03 특성공학과 규제(다중회귀, 변환기, 릿지&라쏘 회귀) (1) | 2024.01.24 |
[혼자 공부하는 머신러닝] 03-2 선형회귀 그리고 다항회귀 (0) | 2024.01.21 |