Hyper Parameter Tuning에 들어가기 앞서, 과대적합에 대해 알아보자.
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
X = cancer.data
y = cancer.target
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier()
tree.fit(X_train, y_train)
pred_train = tree.predict(X_train)
pred_test = tree.predict(X_test)
from sklearn.metrics import accuracy_score
accuracy_score(y_train, pred_train), accuracy_score(y_test, pred_test)
tree.predict(X_train)[:15] #이건 예측 결과
#tree model만 graphviz를 통해 시각화 할 수 있다
from sklearn.tree import export_graphviz
from graphviz import Source
from IPython.display import SVG
graph = Source(export_graphviz(tree #tree - 모델을 알려준 것
, out_file = None
, feature_names = cancer.feature_names #feature 이름들; 무엇을 갖고 비교했는지 이름을 가지고 알려준다; 안 하면 index가지고 하기 때문에 일일이 비교해야 할 수도 있다
, class_names = cancer.target_names #class 이름들
, rounded = True
, filled = True)) #filled : 색을 채워줘서 이해하기 더 편하다
display(SVG(graph.pipe(format='svg')))
# 가장 위에 있는 박스가 가장 중요한, 가장 많이 분류할 수 있는 조건/기준이다
# gini : 순도; 0,1의 비율; 섞여있는 정도; 낮을 수록 어느거 하나로 많이 차있다는 뜻이고, 클수록(0.5에 가까울 수록) 많이 섞여있다는 뜻; 그래서 순도가 0이 될 때까지 갈라진다
# sample : 데이터 양
# value = [a, b] -- 0인애가 a개, 1인애가 b개
# class : 개수가 더 많은 쪽의 클래스
tree2 = DecisionTreeClassifier(max_depth = 3) #최대 3단계 까지만 가지치기를 하라 라는 것
tree2.fit(X_train, y_train)
pred_train = tree2.predict(X_train)
pred_test = tree2.predict(X_test)
accuracy_score(y_train, pred_train), accuracy_score(y_test, pred_test)
depth_list = range(1, 11)
train_acc_list = [] #한번 반복할 때마다 예측 정확도가 나오면 여기에다 저장할 것이다
test_acc_list = [] #여기도
for depth in depth_list:
tree = DecisionTreeClassifier(max_depth = depth)
tree.fit(X_train, y_train) #학습을 시키고
pred_train = tree.predict(X_train) #예측을 해보고
pred_test = tree.predict(X_test) #예측을 해보고
acc_train = accuracy_score(y_train, pred_train) #정확도; 평가지표를 만들어내고
acc_test = accuracy_score(y_test, pred_test) #여기도
train_acc_list.append(acc_train) #그것을 리스트에 담고
test_acc_list.append(acc_test)
import pandas as pd
df = pd.DataFrame({'Train':train_acc_list, 'Test':test_acc_list}, index=depth_list)
df
# max_depth가 1~10 까지의 경우 정확도들 결과가 나왔다.
# train 데이터의 정확도는 계속 상승하지만, test 데이터의 정확도는 어느 시점부터 상승하지 않고 하락한다.
df.plot(figsize=(10,10));
데이터 모델링을 하면서 모델 성능을 높일 수 있는 방법은 크게 (1) 데이터 전처리, (2) 하이퍼파라미터 튜닝이 있을 것이다.
하이퍼 파라미터 (Hyper Parameter)
하이퍼 파라미터 튜닝
최적의 하이퍼파라미터 찾기
1. 만족할 만한 하이퍼파라미터들의 값의 조합을 찾을 때 까지 일일이 수동으로 조정
2. GridSearch 사용
GridSearchCV 매개변수 및 결과조회
estimator
: 모델객체 지정params
: 하이퍼파라미터 목록을 dictionary로 전달('파라미터명':[파라미터값 list] 형식)scoring
: 평가 지표cv
: 교차검증시 fold 개수.n_jobs
: 사용할 CPU 코어 개수 (None:1(기본값), -1: 모든 코어 다 사용)fit(X, y)
: 학습predict(X, y)
: 제일 좋은 성능을 낸 모델로 predict()cv_result_
: 파라미터 조합별 결과 조회best_params_
: 가장 좋은 성능을 낸 parameter 조합 조회best_estimator_
: 가장 좋은 성능을 낸 모델 반환from sklearn.model_selection import GridSearchCV
tree = DecisionTreeClassifier()
# 딕셔너리로 전달
# key: 하이퍼파라미터 명; value: [후보값들] 을 리스트로 전달
param_grid = {
'max_depth':[2,3,4,5,6,7,8], #7개
'min_samples_leaf':[5,10,15,20] #4개 --> 7x4 = 총 28개의 조합
}
grid_search = GridSearchCV(tree
, param_grid = param_grid
, cv = 5 #교차검증시 fold 개수; n번의 교차검증; 데이터들이 돌아가면서 하나씩 검증(validation)에 사용되어 일반화하는 것; 데이터가 많지 않을 때 보통 쓰인다고 함
, n_jobs = -1) #-1: 모든 코어 사용
grid_search.fit(X_train, y_train)
pred_train = grid_search.predict(X_train)
pred_test = grid_search.predict(X_test)
accuracy_score(y_train, pred_train), accuracy_score(y_test, pred_test)
# 찾은 최적의 하이퍼파라미터 조회
grid_search.best_params_ # 준 후보들 중에서 최적을 반환(준 후보들 중이기에 이것보다 더 좋은/적합한 것은 존재할 수 있다.)
# 가장 성능 좋은 estimator(모델)
m = grid_search.best_estimator_ #가장 최적의 하이퍼파라미터 설정을 보여준다
m
accuracy_score(y_train, m.predict(X_train)) # 위에 grid_search한 것이랑 결과가 똑같이 나온느 것을 볼 수 있다; 그게 best를 쓴 것이기에
# 전체 결과 조회
grid_search.cv_results_
# 하지만 보기가 좀 힘들다
# 이렇게 dataframe으로 만들어 보면 좀 더 보기 편하다
import pandas as pd
df = pd.DataFrame(grid_search.cv_results_)
df
# 0~27 -- 총 28개 (다 검증된 것을 볼 수 있다)
# fit_time : 걸린 시간들
# param max, min 부분을 보면 모든 조합을 다 해본 것을 볼 수 있다
# split test score : 각각의 교차검증에 대한 점수; 그리고 평균 점수 (mean), 표준 점수(std), 그리고 순위(rank)
# 이것들 중에 '최적'이 나온 것이다
하지만 그리드 탐색은 조합이 비교적 적어서 보유한 컴퓨팅 자원으로 충분히 실행가능한 경우에만 현실적으로 사용 가능하다. 그렇다면, 만약 후보값이 너무 많을 때/조합이 너무 클 때, 그리드 탐색을 사용하기 어려울 경우엔 어떻게 해야 할까?
이 때엔, RandomizedSearchCV를 이용한 랜덤 탐색을 하는 것이 용이하다.
estimator
: 모델객체 지정param_distributions
: 하이퍼파라미터 목록을 dictionary로 전달 '파라미터명':[파라미터값 list] 형식n_iter
: 파라미터 검색 횟수scoring
: 평가 지표cv
: 교차검증시 fold 개수.n_jobs
: 사용할 CPU 코어 개수 (None:1(기본값), -1: 모든 코어 다 사용)fit(X, y)
: 학습predict(X, y)
: 제일 좋은 성능을 낸 모델로 predict()cv_result_
: 파라미터 조합별 결과 조회best_params_
: 가장 좋은 성능을 낸 parameter 조합 조회best_estimator_
: 가장 좋은 성능을 낸 모델 반환from sklearn.model_selection import RandomizedSearchCV
tree = DecisionTreeClassifier() #여기 괄호 안에 하이퍼파라미터들이 들어가는 곳인데, 여기선 할 필요 없다
param_grid = {
'max_depth':[2,3,4,5,6,7,8], #7개
'min_samples_leaf':[5,10,15,20] #4개 --> 7x4 = 총 28개의 조합
}
n_iter = 5 #파라미터 검색 횟수; 여기선 5번
random_search = RandomizedSearchCV(tree
, param_distributions = param_grid
, n_iter = n_iter
, cv = 5)
random_search.fit(X_train, y_train)
pred_train = random_search.predict(X_train)
pred_test = random_search.predict(X_test)
accuracy_score(y_train, pred_train), accuracy_score(y_test, pred_test)
random_search.best_params_ #최적의 파라미터 조회
random_search.best_estimator_ # 최적의 설정
pd.DataFrame(random_search.cv_results_)
GridSearchCV와 RandomizedSearchCV는 정말이지 편리한 기능이 아닐 수 없다. 최적의 파라미터 값을 알아서 찾아주는 방법, 잘 활용한다면 분명 좋은 성능의 모델을 만드는데 매우 유용할 것이다.