8 분 소요

분류

XGBoost(eXtra Gradient Boost)

XGBoost 개요

항목 설명
뛰어난 예측 성능 일반적으로 분류와 회귀 영역에서 뛰어난 예측 성능을 발휘한다.
GBM 대비
빠른 수행 시간
일반적인 GBM은 순차적으로 Weak learner가 가중치를 증감하는 방법으로 학습하기 때문에 전반적으로 속도가 느리다
하지만 XGBoost는 병렬 수행 및 다양한 기능으로 GBM에 비해 빠른 수행 성능을 보장한다.
아쉽게도 XGBoost가 일반적인 GBM에 수행 시간이 빠르다는 것이지, 다른 머신런이 알고리즘(예를 들어 랜덤 포레스트)에 비해서 빠르다는 의미는 아니다.
과적합 규제
(Reglarization)
표준 GBM의 경우 과적합 규제 기능이 없으나 XGBoost는 자체에 과적합 구제 기능으로 과적합에 좀 더 강한 내구성을 가질 수 있다.
Tree pruning
(나무 가지치기)
일반적으로 GBM은 분할 시 부정 손실이 발생하면 분할을 더 이상 수행하지 않지만, 이러한 방식도 자칫 지나치게 많은 분할을 발생할 수도 있다.
다른 GBM과 마찬가지로 XGBoost도 max_depth 파라미터로 분할 깊이를 조저하기도 하지만, tree pruning으로 더 이상 긍정 이득이 없는 분할을 가지치기 해서 분할 수를 더 줄이는 추가적인 장점을 가지고 있다.
자체 내장된
교차 검증
XGBoost는 반복 수행 시마다 내부적으로 학습 데이터 세트와 평가 데이터 세트에 대한 교차 검증을 수행해 최적화된 반복 수행 횟수를 가질 수 있다.
지정된 반복 횟수가 아니라 교차 검증을 통해 평가 데이터 세트의 평가 값이 최적화 되면 반복을 중간에 멈출 수 있는 조기 중단 기능이 있다.
결손값 자체 처리 XGBoost는 결손값을 자체 처리할 수 있는 기능을 가지고 있다.

XGBoost 파이썬 구현

  1. C/C++ Native Module
    • XGBoost는 최초 c/c++로 작성됨
  2. 파이썬 Wrapper
    • c/c++ 모듈을 호출하는 파이선 Wrapper
  3. 사이킷런 Wrapper
    • 사이킷런 프레임과 통합 될 수 있는 파이썬 Wrapper Class 지원 (XGBClassifier, XGBRegressor)
    • 학습과 예측을 다른 사이킷런 API와 동일하게 fit()과 predict()로 수행
    • GridSearchCV와 같은 다른 사이킷런 모듈과 같이 사용 가능

XGBoost 파이썬 래퍼와 사이킷런 래퍼 API 비교

항목 파이썬 Wrapper 사이킷런 Wrapper
사용 모듈 from xgboost as xgb from xgboost import XGBClassifier
학습용과 테스트용
데이터 세트
DMatrix 객체를 별도 생성
train = xgb.DMatrix(data=X_train, label=y_train)
DMatrix 생성자로 피처 데이터 세트와 레이블 데이터 세트를 입력
넘파이나 판다스를 이용
학습 API Xgb_model=xgb.train()
Xgb_model은 학습된 객체를 반환 받음
XGBClassifer.fit()
예측 API xbg.train()으로 학습된 객체에서 predict() 호출. 즉 Xgb_model.predict()
이때 반환 결과는 예측 결과가 아니라 예측 결과를 추정하는 확률값 반환
XGBClassifer.predict()
예측 결과값 반환
피처 중요도 시각화 plot_importance() 함수 이용 plot_importance() 함수 이용

XGBoost 설치하기

아나콘다 Command 창을 연 뒤 conda install -c anaconda py-xgboost 명령어를 입력한다.

<실습>

#XGBoost 버전 확인
import xgboost

print(xgboost.__version__)
1.5.0

파이썬 래퍼 XGBoost 하이퍼 파라미터

XGBoost 파이썬 래퍼와 사이킷런 래퍼 하이퍼 파라미터 비교

파이썬 Wrapper 사이킷런 Wrapper 하이퍼 파라미터 설명
eta learning_rate GBM의 학습률(learning rate)과 같은 파라미터이다. 0에서 1 사이의 값을 지정하며 부스팅 스텝을 반복적으로 수행할 때 업데이트되는 학습률 값
파이썬 래퍼 기반의 xgboost를 이용할 경우 디폴트는 0.3, 사이킷런 래퍼 클래스를 이용할 경우 eta는 learning_rate 파라미터로 대체되며, 디폴트는 0.1이다.
num_boost_rounds n_estimators 사이킷런 앙상블의 n_estimators와 동일. 약한 학습기의 개수(반복 수행 횟수)
min_child_weight min_child_weight 결정 트리의 min_child_leaf와 유사. 과적합 조절용
max_depth max_depth 결정 트리의 max_depth와 동일. 트리의 최대 깊이
sub_sample subsample GBM의 subsample과 동일. 트리가 커져서 과적합되는 것을 제어하기 위해 데이터를 샘플링하는 비율을 지정한다.
sub_sample=0.5로 지정하면 전체 데이터의 절반을 트리를 생성하는 데 사용한다.
0에서 1 사이의 값이 가능하나 일반적으로 0.5~1 사이의 값을 사용한다.
lambda reg_lambda L2 규제(Regularization) 적용 값이다. 기본값은 1
값이 클 수록 구제 값이 커지며 과적합 제어 효과가 있다.
alpha reg_alpha L1 규제(Regularization) 적용 값이다. 기본값은 0
값이 클 수록 규제 값이 커지며 과적합 제어 효과가 있다.
colsample_bytree colsample_bytree GBM의 max_features와 유사하다.
트리 생성에 필요한 피처(칼럼)를 임의로 샘플링하는 데 사용된다.
매우 많은 피처가 있는 경우 과적합을 조정하는 데 적용한다.
scale_pos_weight scale_pos_weight 특정 값으로 치우친 비대칭한 클래스로 구성된 데이터 세트의 균형을 유지하기 위한 파라미터이다. 기본값은 1
gamma gamma 트리의 리프 노드를 추가적으로 나눌지를결정할 최소 손실 감소 값이다.
해당 값보다 큰 손실(loss)이 감소된 경우에 리프 노드를 분리한다. 값이 클수록 과적합 감소 효과가 있다.

사이킷런 Wrapper의 경우 GBM에 동일한 하이퍼 파라미터가 있다면 이를 사용하고 그렇지 않다면 파이썬 Wrapper의 하이퍼 파라미터를 사용

XGBoost 조기 중단 기능 (Early Stopping)

  • XGBoost는 특정 반복 횟수 만큼 더 이상 비용함수가 감소하지 않으면 지정된 반복횟수를 다 완료하지 않고 수행을 종료할 수 있음
  • 학습을위한 시간을 다축 시킬 수 있음. 특히 최적화 튜닝 단계에서 적절하게 사용 가능
  • 너무 반복 횟수를 단축할 경우 예측 성능 최적화가 안 된 상태에서 학습이 종료 될 수 있으므로 유의 필요
  • 조기 중단 설정을 위한 주요 파라미터
    • early_stopping_rounds: 더 이상 비용 평가 지표가 감소하지 않는 최대 반복횟수
    • eval_metric: 반복 수행 시 사용하는 비용 평가 지표
    • eval_set: 평가를 수행하는 별도의 검증 데이터 세트. 일반적으로 검증 데이터 세트에서 반복적으로 비용 감소 성능 평가

파이썬 래퍼 XGBoost 적용 - 위스콘신 유방암 예측

<실습>

데이터 세트 로딩 하기

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
# xgboost 패키지 로딩하기
import xgboost as xgb
from xgboost import plot_importance

import warnings
warnings.filterwarnings('ignore')

dataset = load_breast_cancer()
features= dataset.data
labels = dataset.target

cancer_df = pd.DataFrame(data=features, columns=dataset.feature_names)
cancer_df['target']= labels
cancer_df.head(3)

mean radius mean texture mean perimeter mean area mean smoothness mean compactness mean concavity mean concave points mean symmetry mean fractal dimension ... worst texture worst perimeter worst area worst smoothness worst compactness worst concavity worst concave points worst symmetry worst fractal dimension target
0 17.99 10.38 122.8 1001.0 0.11840 0.27760 0.3001 0.14710 0.2419 0.07871 ... 17.33 184.6 2019.0 0.1622 0.6656 0.7119 0.2654 0.4601 0.11890 0
1 20.57 17.77 132.9 1326.0 0.08474 0.07864 0.0869 0.07017 0.1812 0.05667 ... 23.41 158.8 1956.0 0.1238 0.1866 0.2416 0.1860 0.2750 0.08902 0
2 19.69 21.25 130.0 1203.0 0.10960 0.15990 0.1974 0.12790 0.2069 0.05999 ... 25.53 152.5 1709.0 0.1444 0.4245 0.4504 0.2430 0.3613 0.08758 0

3 rows × 31 columns

print(dataset.target_names)
print(cancer_df['target'].value_counts())
['malignant' 'benign']
1    357
0    212
Name: target, dtype: int64
# cancer_df에서 feature용 DataFrame과 Label용 Series 객체 추출
# 맨 마지막 칼럼이 Label이므로 Feature용 DataFrame은 cancer_df의 첫번째 칼럼에서 맨 마지막 두번째 컬럼까지를 :-1 슬라이싱으로 추출.
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 )

print(X_train.shape , X_test.shape)
print(X_tr.shape, X_val.shape)
(455, 30) (114, 30)
(409, 30) (46, 30)

학습과 예측 데이터 세트를 DMatrix로 변환

  • DMatrix는 넘파이 array, DataFrame에서도 변환 가능
# 만약 구버전 XGBoost에서 DataFrame으로 DMatrix 생성이 안될 경우 X_train.values로 넘파이 변환. 
# 학습, 검증, 테스트용 DMatrix를 생성. 
dtr = xgb.DMatrix(data=X_tr, label=y_tr)
dval = xgb.DMatrix(data=X_val, label=y_val)
dtest = xgb.DMatrix(data=X_test , label=y_test)

하이퍼 파라미터 설정

params = { 'max_depth':3,
           'eta': 0.05,
           'objective':'binary:logistic',
           'eval_metric':'logloss'
        }
num_rounds = 400

주어진 하이퍼 파라미터와 early stopping 파라미터를 train( ) 함수의 파라미터로 전달하고 학습

# 학습 데이터 셋은 'train' 또는 평가 데이터 셋은 'eval' 로 명기합니다. 
eval_list = [(dtr,'train'),(dval,'eval')] # 또는 eval_list = [(dval,'eval')] 만 명기해도 무방. 

# 하이퍼 파라미터와 early stopping 파라미터를 train( ) 함수의 파라미터로 전달
xgb_model = xgb.train(params = params , dtrain=dtr , num_boost_round=num_rounds , \
                      early_stopping_rounds=50, evals=eval_list )
    [0]	train-logloss:0.65016	eval-logloss:0.66183
    .
    . (생략)
    .
    [126]	train-logloss:0.01973	eval-logloss:0.25587
    .
    . (생략)
    .
    [176]	train-logloss:0.01258	eval-logloss:0.26103

predict()를 통해 예측 확률값을 반환하고 예측 값으로 변환

pred_probs = xgb_model.predict(dtest)
print('predict( ) 수행 결과값을 10개만 표시, 예측 확률 값으로 표시됨')
print(np.round(pred_probs[:10],3))

# 예측 확률이 0.5 보다 크면 1 , 그렇지 않으면 0 으로 예측값 결정하여 List 객체인 preds에 저장 
preds = [ 1 if x > 0.5 else 0 for x in pred_probs ]
print('예측값 10개만 표시:',preds[:10])
predict( ) 수행 결과값을 10개만 표시, 예측 확률 값으로 표시됨
[0.845 0.008 0.68  0.081 0.975 0.999 0.998 0.998 0.996 0.001]
예측값 10개만 표시: [1, 0, 1, 0, 1, 1, 1, 1, 1, 0]
pred_probs
array([0.8447872 , 0.00842587, 0.6796298 , 0.08113331, 0.9751338 ,
       0.9988939 , 0.9983084 , 0.9980654 , 0.99637896, 0.00138468,
       0.00252283, 0.00154995, 0.99780875, 0.99829525, 0.99691856,
       0.9965521 , 0.99120796, 0.9982718 , 0.9970682 , 0.9978916 ,
       0.00202923, 0.10774372, 0.00137198, 0.9989255 , 0.00107862,
       0.7800014 , 0.00295459, 0.00154995, 0.9966723 , 0.05379276,
       0.958738  , 0.00149019, 0.9700533 , 0.8656249 , 0.00678389,
       0.00140975, 0.97810876, 0.99713576, 0.24059245, 0.9972307 ,
       0.35760084, 0.99708337, 0.9919429 , 0.99659145, 0.9962838 ,
       0.9179466 , 0.036952  , 0.997417  , 0.99325067, 0.99804085,
       0.99648905, 0.00236221, 0.9979361 , 0.99784875, 0.9960328 ,
       0.99391055, 0.9984106 , 0.99635327, 0.9967404 , 0.896291  ,
       0.9967794 , 0.9520696 , 0.00349248, 0.00202715, 0.9980167 ,
       0.98225844, 0.00349248, 0.99056447, 0.9972249 , 0.9978916 ,
       0.00297725, 0.99731344, 0.00163038, 0.98887384, 0.9962419 ,
       0.00137198, 0.9985329 , 0.9985329 , 0.99858946, 0.00131184,
       0.00139682, 0.93810165, 0.9969139 , 0.99748176, 0.992568  ,
       0.9906398 , 0.9914522 , 0.9930942 , 0.9830724 , 0.00137198,
       0.19445673, 0.99830306, 0.00650652, 0.00560008, 0.99777275,
       0.00793959, 0.02962515, 0.99509096, 0.00236221, 0.78849   ,
       0.00614955, 0.00250252, 0.99592257, 0.99598455, 0.6040961 ,
       0.9969748 , 0.99688077, 0.8580849 , 0.9966723 , 0.9985133 ,
       0.6028515 , 0.97962165, 0.99558735, 0.9978284 ], dtype=float32)

get_clf_eval( )을 통해 예측 평가

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=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_proba)
    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))
get_clf_eval(y_test , preds, pred_probs)
오차 행렬
[[34  3]
 [ 2 75]]
정확도: 0.9561, 정밀도: 0.9615, 재현율: 0.9740,    F1: 0.9677, AUC:0.9937

Feature Importance 시각화

import matplotlib.pyplot as plt
%matplotlib inline

fig, ax = plt.subplots(figsize=(10, 12))
plot_importance(xgb_model, ax=ax)
<AxesSubplot:title={'center':'Feature importance'}, xlabel='F score', ylabel='Features'>

output_21_1

사이킷런 래퍼 XGBoost의 개요 및 적용

<실습>

사이킷런 래퍼 클래스 임포트, 학습 및 예측

# 사이킷런 래퍼 XGBoost 클래스인 XGBClassifier 임포트
from xgboost import XGBClassifier

# Warning 메시지를 없애기 위해 eval_metric 값을 XGBClassifier 생성 인자로 입력. 미 입력해도 수행에 문제 없음.   
xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.05, max_depth=3, eval_metric='logloss')
xgb_wrapper.fit(X_train, y_train, verbose=True)
w_preds = xgb_wrapper.predict(X_test)
w_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]
get_clf_eval(y_test , w_preds, w_pred_proba)
오차 행렬
[[34  3]
 [ 1 76]]
정확도: 0.9649, 정밀도: 0.9620, 재현율: 0.9870,    F1: 0.9744, AUC:0.9954

early stopping을 50으로 설정하고 재 학습/예측/평가

from xgboost import XGBClassifier

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.05, max_depth=3)
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)

ws50_preds = xgb_wrapper.predict(X_test)
ws50_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]
[0]	validation_0-logloss:0.65016	validation_1-logloss:0.66183
.
. (생략)
.
[126]	validation_0-logloss:0.01973	validation_1-logloss:0.25587
.
. (생략)
.
[175]	validation_0-logloss:0.01267	validation_1-logloss:0.26086
get_clf_eval(y_test , ws50_preds, ws50_pred_proba)
오차 행렬
[[34  3]
 [ 2 75]]
정확도: 0.9561, 정밀도: 0.9615, 재현율: 0.9740,    F1: 0.9677, AUC:0.9933

early stopping을 10으로 설정하고 재 학습/예측/평가

# early_stopping_rounds를 10으로 설정하고 재 학습. 
xgb_wrapper.fit(X_tr, y_tr, early_stopping_rounds=10, 
                eval_metric="logloss", eval_set=evals,verbose=True)

ws10_preds = xgb_wrapper.predict(X_test)
ws10_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]
get_clf_eval(y_test , ws10_preds, ws10_pred_proba)
    [0]	validation_0-logloss:0.65016	validation_1-logloss:0.66183
    .
    . (생략)
    .
    [93]	validation_0-logloss:0.03107	validation_1-logloss:0.25865
   .
   . (생략)
   .
    [102]	validation_0-logloss:0.02714	validation_1-logloss:0.25901
오차 행렬
[[34  3]
 [ 3 74]]
정확도: 0.9474, 정밀도: 0.9610, 재현율: 0.9610,    F1: 0.9610, AUC:0.9933
from xgboost import plot_importance
import matplotlib.pyplot as plt
%matplotlib inline

fig, ax = plt.subplots(figsize=(10, 12))
# 사이킷런 래퍼 클래스를 입력해도 무방. 
plot_importance(xgb_wrapper, ax=ax)
<AxesSubplot:title={'center':'Feature importance'}, xlabel='F score', ylabel='Features'>

output_31_1