리프 중심 트리 분할
(Leaf Wise)방식을 사용한다.주요파라미터
Learning Task 파라미터
사아킷런 래퍼 LightGBM의 하이퍼 파라미터는 사이킷런 XGBoost에 맞춰서 변경하여 많은 하이퍼 파라미터가 똑같다.
# LightGBM - 위스콘신 유방암 예측
from lightgbm import LGBMClassifier
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()
ftr = dataset.data
target = dataset.target
# 전체 데이터 80, 20 추출
x_train, x_test, y_train, y_test = train_test_split(ftr, target, test_size = 0.2, random_state=156)
# XGBoost와 동일하게 n_estimators 400 설정
lgbm_wrapper = LGBMClassifier(n_estimators=400)
# LightGBM도 XGBoost와 동일하게 조기 중단 수행
evals = [(x_test, y_test)]
lgbm_wrapper.fit(x_train, y_train, early_stopping_rounds=100, eval_metric='logloss',
eval_set=evals, verbose=True)
preds = lgbm_wrapper.predict(x_test)
pred_proba = lgbm_wrapper.predict_proba(x_test)[:,1]
# get_clf_eval 활용
# XGB 모델 예측 성능 평가
from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.metrics import precision_score, recall_score
from sklearn.metrics import f1_score, roc_auc_score
def get_clf_eval(y_test , pred):
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_score(y_test, pred)
print('오차 행렬')
print(confusion)
print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f},\
F1: {3:.4f}, AUC:{4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))
get_clf_eval(y_test, preds)
# 시각화
from lightgbm import plot_importance
import matplotlib.pyplot as plt
%matplotlib inline
fig, ax = plt.subplots(figsize=(10,12))
plot_importance(lgbm_wrapper, ax = ax)
지금까지는 GridSearchCV를 이용하여 하이퍼 파라미터 튜닝을 수행했다. 하이퍼 파라미터의 수가 많은 XGBoost나 LightGBM과 같은 모델은 GridSearchCV를 이용하여 튜닝 시 많은 수행 시간이 요구된다. (저 모델들이 하이퍼 파라미터가 상대적으로 많기 때문...!)
그렇다면 더 효율적인 하이퍼 파라미터 방식이 있을까? 바로 베이지안 최적화 기반의 HyperOpt가 있겠다!
목적 함수의 식을 제대로 알 수 없는 함수에서, 최대 또는 최소의 함수 반환 값을 만드는 최적 입력값을 가능한 적은 시도를 통해 빠르고 효과적으로 찾아주는 방식
베이지안 확률에 기반을 두고 있는 최적화 기법
베이지안 최적화의 주요 요소
- 대체 모델 (Surrogate Model)
- 획득 함수 (Acquisition Function)
대체 모델은 획득 함수로부터 최적 함수를 예측할 수 있는 입력값을 추천받고 이를 기반으로 최적 함수 모델 개선, 획득 함수는 개선된 대체 모델을 기반으로 최적 입력값을 계산하는 프로세스
이때, 입력값은 하이퍼 파라미터에 해당함, 즉, 대체 모델은 획득 함수로부터 하이퍼 파라미터를 추천받아 모델 개선 수행, 획득 함수는 개선된 모델을 바탕으로 더 정확한 하이퍼 파라미터를 계산함!
위에서 정리한 베이지안 최적화 프로세스 2단계에서 대체 모델은 최적 함수를 추정할 때 다양한 알고리즘을 사용할 수 있다. 일반적으로는 가우시안 프로세스 (Gaussian Process) 를 적용하지만, HyperOpt는 트리 파르젠 Estimator (TPE, Tree-structure Parzen Estimator) 를 사용한다.
HyperOpt는 다음과 같은 프로세스를 통해 사용할 수 있다.
!pip install hyperopt
# p257
## 검색 공간 설정
# hp 모듈을 사용하여 입력 변수명 및 검색 공간 설정
from hyperopt import hp
#-10 ~ 10까지 1긴격을 가지는 입력변수 x와 -15~ 15까지 1간격으로 입력 변수 y설정.
search_space = {"x": hp.quniform("x",-10,10,1),
"y":hp.quniform("y",-15,15,1)}
from hyperopt import STATUS_OK
# 목적 함수르 생성.
# 변숫값과 변수 검색 공간을 가지는 딕셔너리를 인자로 받고, 특정 값을 반환
def objective_func(search_space):
x = search_space["x"]
y = search_space["y"]
retval= x**2 -20*y
return retval
from hyperopt import fmin, tpe, Trials
import numpy as np
# 입력 결과값을 저장한 Trials 객체값 생성
trial_val = Trials()
# 목적 함수의 최솟값을 반혼하는 최적 입력 변숫값을 5번의 입력값 시도(max_evals= 5)로 찾아냄.
## fmin() 함수는 아래의 주요 인자를 가짐
best_01 = fmin(fn=objective_func, ## 목적 함수
space=search_space, ## 검색 공간
algo=tpe.suggest, ## 베이지안 최적화 적용 알고리즘
max_evals=5, ## 입력 시도 횟수
trials=trial_val ## 시도한 입력 값 및 입력 결과 저장
) ## fmin()을 시도할 때마다 동일한 결과를 가질 수 있도록 설정하는 랜덤 시드
print("best:",best_01)
import numpy as np
trial_val = Trials()
# 목적 함수의 최솟값을 반혼하는 최적 입력 변숫값을 5번의 입력값 시도(max_evals= 5)로 찾아냄.
best_02 = fmin(fn=objective_func, space=search_space,
algo=tpe.suggest, max_evals=20,
trials=trial_val)
print(best_02)
# trial_val의 results 및 vals 확인
trial_val.results
trial_val.vals
import pandas as pd
losses = [loss_dict['loss'] for loss_dict in trial_val.results]
result_df = pd.DataFrame(
{
'x':trial_val.vals['x'],
'y':trial_val.vals['y'],
'losses':losses
}
)
result_df
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
### 데이터 로드
## 유방암 데이터셋 로드
dataset = load_breast_cancer()
features = dataset.data
labels = dataset.target
## 데이터를 Pandas DataFrame으로 로드
cancer_df = pd.DataFrame(data=features, columns=dataset.feature_names)
cancer_df['target'] = labels
cancer_df.head(5)
### 데이터 분리
## 학습 및 검증 데이터셋으로 데이터 분리
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_tr,X_val,y_tr,y_val = train_test_split(X_train, y_train, test_size=0.1,random_state=156)
##1. 검색 공간 설정
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),
}
## 2. 목적 함수 설정 p264
## 검색 공간에서 설정한 하이퍼 파라미터들을 입력 받아서 XGBoost를 학습시키고, 평가 지표를 반환하도록 구성되어야 함.
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):
# 수행 시간 절약을 위해 nestimators는 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}
## 3. fmin()을 사용하여 최적 하이퍼 파라미터 찾기
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)
## 모델 로드
# 획득한 최적의 하이퍼 파라미터를 이용하여 모델 선언
xgb_wrapper = XGBClassifier(n_estimators=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)
)
## 모델 학습
## early stopping
evals = [(X_tr, y_tr), (X_val, y_val)]
## model train
xgb_wrapper.fit(
X_tr, y_tr,
early_stopping_rounds=50,
eval_metric='logloss',
eval_set=evals,
verbose=True
)
## 모델 평가
## eval
preds = xgb_wrapper.predict(X_test)
pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]
get_clf_eval(y_test, preds, pred_proba)
GridSearchCV를 이용하여 XGBoost, LightGBM 하이퍼 파라미터를 튜닝할 경우 수행 시간이 오래 걸린다는 단점이 있다. 이때 생각할 수 있는 것이 바로 베이지안 최적화 기반의 HyperOpt이다.
HyperOpt
캐글의 산탄데르 고객 만족 데이터셋에 대해 LigthGBM과 XGBoost를 활용하여 예측한다. feature은 총 370개, 클래스 레이블 명은 TARGET이고, 이때 해당 값이 1이면 불만을 가진 고객, 0이면 만족한 고객을 의미한다.
이때, 불균형 데이터셋이므로 모델 성능 평가는 정확도가 아닌 roc-auc로 진행한다.
데이터 확인
370개의 feature, 1개의 class 열로 구성된 dataframe
260개의 정수형 feature, 111개의 실수형 feature로 구성됨
결측값은 없음
출처:
https://asthtls.tistory.com/m/1277
https://velog.io/@bansohi/ML-ch4.8
https://velog.io/@sset2323/04-07.-LightGBM