TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 머신 | 딥러닝 & AI>

[파이썬 머신러닝] 분류 > 베이지안 최적화 (2)

by 기록자_Recordian 2024. 7. 7.
728x90
반응형
시작에 앞서
해당 내용은 '<파이썬 머신러닝 완벽 가이드> 권철민 지음. 위키북스' 를 토대로 작성되었습니다. 보다 자세한 내용은 해당 서적에 상세히 나와있으니 서적을 참고해 주시기 바랍니다.

이전 내용
 

[파이썬] 분류 > 베이지안 최적화 (1)

시작에 앞서해당 내용은 ' 권철민 지음. 위키북스' 를 토대로 작성되었습니다. 보다 자세한 내용은 해당 서적에 상세히 나와있으니 서적을 참고해 주시기 바랍니다.베이지안 최적화 XGBoost나 Ligh

puppy-foot-it.tistory.com


HyperOpt를 이용한 XGBoost 하이퍼 파라미터 최적화

 

위스콘신 유방암 데이터 세트를 이용하여 HyperOpt를 이용한 XGBoost의 하이퍼 파라미터를 최적화를 수행해본다.

 

[HpyerOpt를 이용한 XGBoost 하이퍼 파라미터 최적화 방법]

- 적용해야 할 하이퍼 파라미터와 검색 공간 설정

- 목적 함수에서 XGBoost 학습 후 에측 성능 결과를 반환 값으로 설정

- fmin() 함수에서 목적 함수를 하이퍼 파라미터 검색 공간의 입력값들을 사용하여 최적의 예측 성능 결과를 반환하는 최적 입력값들을 결정

※ 단, HyperOpt는 입력값과 반환값이 모두 실수형이기 때문에 하이퍼 파라미터 입력 시 형변환을 해줘야 하고,

HpyerOpt 목적 함수는 최솟값을 반환할 수 있도록 최적화해야 하기 때문에 성능 값이 클수록 좋은 성능 지표일 경우 -1을 곱해줘야 한다.

# 위스콘신 유방암 예측 (HyperOpt 활용)

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

dataset = load_breast_cancer()

cancer_df = pd.DataFrame(data=dataset.data, columns=dataset.feature_names)
cancer_df['target']=dataset.target
X_features = cancer_df.iloc[:, :-1]
y_label = cancer_df.iloc[:, -1]

# 전체 데이터 중 80% 학습 데이터, 20% 테스트 데이터
X_train, X_test, y_train, y_test = train_test_split(X_features, y_label, test_size=0.2, random_state=156)

# 위에서 만든 X_train, y_train을 다시 쪼개 90% 학습, 10% 검증용 데이터 분리
X_tr, X_val, y_tr, y_val = train_test_split(X_train, y_train, test_size=0.1, random_state=156)

 

◆ 하이퍼 파라미터 검색 공간 설정

max_depth, min_child_weight는 정수형 하이퍼 파라미터 이므로 hp.quniform을,

learning_rate, colsample_bytree는 hp.uniform 사용

from hyperopt import hp

# max_depth는 5에서 20까지 1간격으로, min_child_weight는 1에서 2까지 1간격으로
# colsample_bytree는 0.5에서 1사이, learning_rate는 0.01에서 0.2 사이 정규 분포된 값으로 검색
xgb_search_space= {'max_depth': hp.quniform('max_depth', 5, 20, 1),
                   'min_child_weight': hp.quniform('min_child_weight', 1, 2, 1),
                   'learning_rate': hp.uniform('learning_rate', 0.01, 0.2),
                   'colsample_bytree':hp.uniform('colsample_bytree', 0.5, 1)
                  }

 

◆ 목적 함수 설정

하이퍼 파라미터 튜닝을 위한 목적 함수는 검색 공간에서 설정한 하이퍼 파라미터들을 입력 받아서 XGBoost를 학습하고 평가지표를 반환할 수 있도록 구성.

 

[유의할 점]

- 검색 공간에서 목적 함수로 입력되는 모든 인자들은 실수형 값이므로 이들을 XGBoostClassifier의 정수형 하이퍼 파라미터값으로 설정할 때는 정수형으로 형변환을 해야 한다.

예. XGBoostClassifier(max_depth=int(search_space['max_depth']))

 

- HpyerOpt의 목적 함수는 최솟값을 반환할 수 있도록 최적화해야 하기 때문에 정확도와 값이 클수록 좋은 성능 지표일 경우 -1을 곱한 뒤 반환하여, 더 큰 성능 지표가 더 작은 반환값이 되도록 만들어줘야 한다.

from sklearn.model_selection import cross_val_score
from xgboost import XGBClassifier
from hyperopt import STATUS_OK

#fmin()에서 입력된 search_space 값으로 입력된 모든 값은 실수형인
#XGBClassifier의 정수형 하이퍼 파라미터는 정수형 변환을 해줘야 함
#정확도는 높을수록 더 좋은 수치임 -1* 정확도를 곱해서 큰 정확도 값일수록 최소가 되도록 변환
def objective_func(search_space):
    #수행 시간 절약을 위해 n_estimators는 100으로 축소
    xgb_clf = XGBClassifier(n_estimators=100, max_depth=int(search_space['max_depth']),
                            min_child_weight=int(search_space['min_child_weight']),
                            learning_rate=search_space['learning_rate'],
                            colsample_bytree=search_space['colsample_bytree'],
                            eval_metric='logloss')
    accuracy = cross_val_score(xgb_clf, X_train, y_train, scoring='accuracy', cv=3)

    # accuracy는 cv=3 개수만큼 roc-auc 결과를 리스트로 가짐. 이를 평균해서 반환하되 -1 곱합
    return {'loss':-1 * np.mean(accuracy), 'status':STATUS_OK}

 

◆ fmin() 을 이용해 최적 하이퍼 파라미터 도출

최대 반복 횟수 max_evals 는 50,

앞서 설정한 목적 함수 objective_func, 검색 공간 xgb_search_space 등을 인자로 입력rstate는 np.random.default_rng(seed=9)) 로 설정

from hyperopt import fmin, tpe, Trials

trial_val = Trials()

best = fmin(fn=objective_func,
               space=xgb_search_space,
               algo=tpe.suggest,
               max_evals=50, #최대 반복 횟수 지정
               trials=trial_val,
               rstate=np.random.default_rng(seed=9))
print('best:', best)

▶ best 출력 결과

colsample_bytree가 0.54241, learning_rate가 0.12601, max_depth가 17.0, min_child_weight가 2.0 이 도출되었다.

여기서 정수형 파라미터인 max_depth, min_child_weight가 실수형 값으로 도출되었다.

 

◆ 최적 하이퍼 파라미터 변환

추출된 최적 하이퍼 파라미터를 직접 XGBClassifier에 인자로 입력하기 전에 정수형 하이퍼 파라미터는 정수형으로 형 변환을, 실수형 하이퍼 파라미터는 소수점 5자리까지만 변환

print('colsample_bytree:{0}, learning_rate:{1}, max_depth:{2}, min_child_weight:{3}'.format(round(best['colsample_bytree'], 5),
                                                                                            round(best['learning_rate'], 5),
                                                                                            int(best['max_depth']),
                                                                                            int(best['min_child_weight'])))

 

◆ 성능 평가 확인

도출된 최적 하이퍼 파라미터들을 이용해서 XGBClassifier를 재학습한 후 성능 평가 결과를 확인

XGBoost의 조기 중단을 검증 데이터 세트로 활용하며 n_estimators는 400으로 증가시키고,

앞서 사용되었던 clf_get_eval( ) 을 이용.

from sklearn.metrics import roc_auc_score
from sklearn.metrics import roc_curve
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix
from sklearn.metrics import f1_score

def get_clf_eval(y_test, pred=None, pred_proba=None):
    confusion = confusion_matrix(y_test, pred)
    accuracy = accuracy_score(y_test, pred)
    precision = precision_score(y_test, pred)
    recall = recall_score(y_test, pred)
    f1 = f1_score(y_test, pred)
    # ROC-AUC 추가
    roc_auc = roc_auc_score(y_test, pred)
    print('오차 행렬')
    print(confusion)
    # ROC-AUC print 추가
    print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f},\
        F1: {3:.4f}, AUC: {4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))
xgb_wrapper = XGBClassifier(n_estiamtors=400,
                            learning_rate=round(best['learning_rate'], 5),
                            max_depth=int(best['max_depth']),
                            min_child_weight=int(best['min_child_weight']),
                            colsample_bytree=round(best['colsample_bytree'], 5)
                           )

evals = [(X_tr, y_tr), (X_val, y_val)]
xgb_wrapper.fit(X_tr, y_tr, early_stopping_rounds =50, eval_metric='logloss',
                eval_set=evals, verbose=True)


preds = xgb_wrapper.predict(X_test)
pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]

get_clf_eval(y_test, preds, pred_proba)


 

728x90
반응형