04-06. XGBoost(eXtra Gradient Boost)

Park Jong Hun·2021년 2월 22일
2

위키북스의 파이썬 머신러닝 완벽 가이드 책을 토대로 공부한 내용입니다.


1. XGBoost 개요


XGBoost는 트리 기반의 앙상블 학습에서 가장 각광받고 있는 알고리즘 중 하나이다. 압도적인 수치의 차이는 아니지만, 분류에 있어서 일반적으로 다른 머신러닝보다 뛰어난 예측 성능을 나타낸다. XGBoost는 GBM에 기반하고 있지만, GBM의 단점은 느린 수행 시간 및 과적합 규제(Regulartization) 부재 등의 문제를 해결해야 매우 각광을 받고 있다. 특히 XGBoost는 병렬 CPU 환경에서 병력 학습이 가능해 기존 GBM보다 빠르게 학습을 완료할 수 있다.

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

XGBoost의 핵심 라이브러리는 C/C++로 작성되어 있고, 파이썬에 제공되는 XGBoost 패키지는 대부분 C/C++ 핵심 라이브러리를 호출하는 것이다. XGBoost 파이썬 패키지의 이름은 'xgboost'이고, 초기에는 사이킷런과 호환되지 않는 독자적인 패키지였으나 파이썬 기반의 머신러닝 사용자들이 사이킷런을 많이 사용하고 있어서 사이킷런과 호환 가능한 래퍼 클래스(Wrapper class)를 제공하기로 했다. XGBoost의 사이킷런 래퍼 클래스는 XGBClassifier와 XGBRegressor이다. 이를 사이킷런 estimator의 학습을 위한 fit(), predict() 과 같은 method를 사용할 수 있다. 구분을 위해 초기의 독자적인 XGBoost 프레임워크 기반의 XGBoost를 파이썬 래퍼 XGBoost 모듈이라 하고, 사이킷런과 연동되는 모듈을 사이킷런 XGBoost 모듈이라고 하겠다.


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


XGBoost는 GBM과 유사한 hyper parameter를 동일하게 가지고 있고, 조기 중단(Early Stopping), 과적합을 규제하기 위한 hyper parameter 등이 추가되었다. 파이썬 래퍼 XGBoost 하이퍼 파라미터를 유형별로 나누면 아래와 같다.

  • 일반 파라미터 : 일반적으로 실행 시 스레드의 개수나 silent 모드 등의 선택을 위한 파라미터로서 디폴트 파라미터 값을 바꾸는 경우는 거의 없다.
  • 부스터 파라미터 : 트리 최적화, 부스팅, regularization 등과 관련 파라미터 등을 지칭하며 대부분의 파라미터들은 여기에 속한다.
  • 학습 태스크 파라미터 : 학습 수행 시의 객체 함수, 평가를 위한 지표 등을 설정하는 파라미터이다.

주요 일반 파라미터

  • booster : gbtree(tree based model) 또는 gblinear(linear model) 선택, default는 gbtree이다.
  • silent : default는 0이며, 출력 메세지를 나타내고 싶지 않을 경우 1로 설정한다.
  • nthread : CPU의 실행 스레드 개수를 조정하며, default는 CPU의 전체 스레드를 다 사용하는 것이다. 멀티 코어/스레트 CPU 시스템에서 전체 CPU를 사용하지 않고 일부 CPU만 사용해 ML 애플리케이션을 구동하는 경우에 변경한다.

주요 부스터 파라미터

  • eta [default=0.3, alias: learning_rate] : GBM의 학습률(learning rate)과 같은 파라미터이다. 0에서 1 사이의 값을 지정하며 부스팅 스텝을 반복적으로 수행할 때 업데이트되는 학습률 값, 파이썬 래퍼 기반의 xgboost를 이용할 경우 default는 0.3이고 사이킷런 래퍼 클래스를 이용할 경우 eta는 learning_rate 파라미터로 대체되며, default는 0.1이다. 보통은 0.01 ~ 0.2 사이의 값을 선호한다.
  • num_boost_rounds : GBM의 n_estimators와 같은 파라미터이다.
  • min_child_weight [default=1] : 트리에서 추가적으로 가지를 나눌지를 결정하기 위해 필요한 데이터들의 weight 총합, min_child_weight가 클수록 분할을 자제한다. 과적합을 조절하기 위해 사용된다.
  • gamma [default=0, alias: min_split_loss] : 트리의 리프 노드를 추가적으로 나눌지를 결정할 최소 손실 감소 값이다. 해당 값보다 큰 손실(loss)이 감소된 경우에 리프 노드를 분리한다. 값이 클수록 과적합 감소 효과가 있다.
  • max_depth [default=6] : 트리 기반 알고리즘의 max_depth와 같다. 0을 지정하면 깊이에 제한이 없다. max_depth가 높으면 특정 피쳐 조건에 특화되어 룰 조건이 만들어지므로 과적합 가능성이 높아지며 보통은 3~10 사이의 값을 적용한다.
  • sub_sample [default=1] : GBM의 subsample과 동일하다. 트리가 커져서 과적합되는 것을 제어하기 위해 데이터를 샘플링하는 비율을 지정한다. sub_sample=0.5로 지정하면 전체 데이터의 절반을 트리를 생성하는 데 사용한다. 0에서 1사이의 값이 가능하나 일반적으로 0.5 ~ 1 사이의 값을 사용한다.
  • colsample_bytree [default=1] : GBM의 max_feature와 유사하다. 트리 생성에 필요한 피처(column)를 임의로 샘플링하는 데 사용된다. 매우 많은 피처가 있는 경우 과적합을 조정하는 데 적용하다.
  • lambda [default=1, alias: reg_lambda] : L2 Regularation 적용 값이다. 피처 개수가 많을 경우 적용을 검토하며 값이 클수록 과적합 감소 효과가 있다.
  • alpha [default=0, alias: reg_alpha] : L1 Regularization 적용 값이다. 피처 개수가 많을 경우 적용을 검토하며 값이 클수록 과적합 감소 효과가 있다.
  • scale_pos_weight [default=1] : 특정 값으로 치우친 비대칭한 클래스로 구성된 datase의 균형을 유지하기 위한 파라미터이다.

학습 태스크 파라미터

  • objective : 최솟값을 가져야할 손실 함수를 정의합니다. XGBoost는 많은 유형의 손실함수를 사용할 수 있습니다. 주로 사용되는 손실함수는 이진 분류인지 다중 분류인지에 따라 달라진다.
  • binary:logitic : 이진 분류일 때 적용한다.
  • multi:softmax : 다중 분류일 때 적용한다. 손실함수가 multi:softmax일 경우에는 label 클래스의 개수인 num_class parameter를 지정해야 한다.
  • multi:softprob : multi:softmax와 유사하나 개별 label 클래스의 해당되는 예측 확률을 반환한다.
  • eval_metric : 검증에 사용되는 함수를 정의한다. defalut는 회귀인 경우는 rmse, 분류일 경우에는 error이다. 다음은 eval_metric의 값 유형들이다.
    • rmse : Root Mean Square Error
    • mae : Mean Absolute Error
    • logloss : Negative log-likelihood
    • error : Binary classification error rate (0.5 threshold)
    • merror : Multiclass classification error rate
    • mloglose : Multiclass logloss
    • auc : Area under the curve

과적합 문제가 심각하다면 다음과 같이 적용할 것을 고려할 수 있다.

  • eta 값을 낮춘다.(0.01 ~ 0.1) 그리고 eta 값을 낮추면 num_round(또는 n_estimator)는 반대로 높여준다.
  • max_depth 값을 낮춘다.
  • min_child_weight 값을 높인다.
  • gamma 값을 높인다.
  • 또한 subsample과 colsample_bytree를 조정하는 것도 트리가 너무 복잡하게 생성되는 것을 막아 과적합 문제에 도움이 될 수 있다.

XGBoost는 자체적으로 교차 검증, 성능 평가, feature 중요도 등의 시각화 기능을 가지고 있고, 기본 GBM에서 부족한 다른 여러 성능 향상 기능이 있다. 그 중 수행 속도를 향상시키기 위한 대표적인 기능을 조기 중단(Early Stopping) 기능이 있는데, 이 기능 덕분에 n_estimator에 지정한 부스팅 반복 횟수에 도달하지 않더라고 예측 오류가 더 이상 개선되지 않으면 반복을 끝까지 수행하기 않고 중지해 수행 시간을 개선할 수 있다.


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


위스콘신 유방암 dataset은 종양의 크기, 모양 등의 다양한 속성값을 기반으로 악성 종양(malignment)인지 양성 종양(benign)인지를 분류한 dataset이다. 양성 종양이 비교적 성장 속도가 느리고 전이되지 않는 것에 반해, 악성 종양은 주위 조직에 침입하면서 빠르게 성장하고 신체 각 부위에 확산되거나 전이되어 생명을 위협한다.

import xgboost as xgb
from xgboost import plot_importance
import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import warnings
warnings.filterwarnings('ignore')

dataset = load_breast_cancer()
X_features= dataset.data
y_label = dataset.target

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

print(dataset.target_names)
print(cancer_df['target'].value_counts())

[output] dataset의 많은 속석 값이 숫자형으로 되어 있고, 양성이 357개, 음성이 212개로 구성되어 있다. 사이킷런과 다른 점은 학습/테스트를 위한 DMatrix를 생성한다는 점이고, DMatrix는 numpy 입력 파라미터를 받아 만들어지는 XGBoost만의 전용 dataset이다. 주요 입력 파라미터는 data와 label이다.

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

dtrain = xgb.DMatrix(data=X_train , label=y_train)
dtest = xgb.DMatrix(data=X_test , label=y_test)

[output] 파이썬 래퍼 XGBoost 모듈인 xgboost를 이용하여 학습을 수행하기 전에 먼저 하이퍼 파라미터를 설정해야한다. XGBoost의 hyper parameter는 주로 딕셔너리 형태로 입력한다. 그리고 조기 중단은 XGBoost가 수행 성능을 개선하기 위해서 더 이상 지표 개선이 없을 경우에 num_boost_round 횟수를 모두 채우지 않고 중간에 반복을 빠져 나올 수 있도록 하는 것이다. train() 함수에서 early_stopping_rounds 파라미터를 입력하여 조기 중단 할 수 있는 최소 반복 횟수를 설정할 수 있다. trian 함수의 evals를 이용해 학습이 반복될 때마다 표시된 dataset에 대한 평가 지표 결과가 출력된다.

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

# train 데이터 셋은 ‘train’ , evaluation(test) 데이터 셋은 ‘eval’ 로 명기합니다. 
wlist = [(dtrain,'train'),(dtest,'eval') ]
# 하이퍼 파라미터와 early stopping 파라미터를 train( ) 함수의 파라미터로 전달
xgb_model = xgb.train(params=params, dtrain=dtrain, num_boost_round=num_rounds, early_stopping_rounds=100, evals=wlist)

[output]

......

train() 함수로 모델을 학습이 완료되면 학습이 완료된 모델 객체를 반환하고, 이 모델 객체는 예측을 위해 predict() method를 이용한다. 유의할 점은 사이킷런의 predict() method는 예측 결과 클래스인 0 혹은 1을 반환하는데, xgboost는 결과 값이 아닌 예측 결과를 추정할 수 있는 확률 값을 반환한다.

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])

[output] 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)

[output] xgboost의 plot_importance() API는 feature의 중요도를 막대그래프 형식으로 나타낸다. 기본 평가 지표로 f1 score를 기반으로 각 feature의 중요도를 나타낸다. 내장된 plot_importance() 이용 시 유의할 점은 xgboost 넘파이 기반의 feature 데이터로 학습 시 feature 명을 알 수 없으므로 f0, f1과 같이 feature 순서별로 f자 뒤에 순서를 붙여서 축에 나열해준다.

import matplotlib.pyplot as plt
%matplotlib inline

fig, ax = plt.subplots(figsize=(10, 12))
plot_importance(xgb_model, ax=ax)

[output] 결정 트리에서 보여준 트리 기반 규칙 구조도 xgboost에서 시각화할 수 있다. to_graphviz() API를 이용하면 되지만 결정 트리와 마찬가지로 Graphviz 프로그램과 패키지를 설치해야한다. 그리고 사이킷런의 GridSearchCV와 유사하게 교차 검증 수행 후 최적 파라미터를 구할 수 있는 cv() API도 제공한다.


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


사이킷런 래퍼 XGBoost는 사이킷런의 기본 Estimator를 그대로 상속하여 만들었기 때문에 fit()과 predict()만으로 학습과 예측이 가능하고, 다른 유틸리티들도 사용 가능하다. 또한 기존의 다른 머신러닝 알고리즘으로 만들어놓은 프로그램이 있더라도 알고리즘 클래스만 XGBoost 래퍼 클래스로 바꾸면 그대로 사용 가능하다. 사이킷런 래퍼 XGBoost는 크게 분류를 위한 XGBClassifier와 회귀를 위한 XGBRegressor가 있다. 파이썬 래퍼 XGBoost와 사이킷런 래퍼 XGBoost의 하이퍼 파라미터에 약간의 차이가 있는데 기존 사이킷런에서 일반적으로 사용하던 하이퍼 파라미터와의 호환성을 유지하기 위해 기존 xgboost 모듈에서 사용하던 파라미터 중 몇개를 바꾸었다.

  • eta -> learning_rate
  • sub_sample -> subsample
  • lambda -> reg_lambda
  • alpha -> reg_alpha
    또한 xgboost의 n_estimator와 num_boost_round 파라미터는 동일한 파라미터이다. 만약 동시에 사용되면 n_estimator가 무시된다. 파이썬 래퍼 XGBoost와 동일하게 위스콘신 유방암 dataset을 사용해보겠다.
# 사이킷런 래퍼 XGBoost 클래스인 XGBClassifier 임포트
from xgboost import XGBClassifier

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)
xgb_wrapper.fit(X_train, y_train)
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)

[output] 파이썬 래퍼 XGBoost와 동일한 평가 결과가 나온다. 조기 중단 파라미터는 fit()에 입력하면 되는데 평가 지표가 향상될 수 있는 반복 횟수를 정의하는 early_stopping_rounds, 조기 중단을 위한 평가 지표인 eval_metric, 그리고 성능 평가를 수행할 dataset인 eval_set이다.

from xgboost import XGBClassifier

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)
evals = [(X_test, y_test)]
xgb_wrapper.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="logloss", 
                eval_set=evals, verbose=True)

ws100_preds = xgb_wrapper.predict(X_test)
ws100_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]

[output]

......

n_estimator를 400으로 설정하였는데 311에서 학습이 완료하였다. 이는 211번과 311번까지 early_stopping_rouns로 설정된 100번의 반복 동안 성능 평가 지수가 향상되지 않았기 때문이다.

get_clf_eval(y_test , ws100_preds, ws100_pred_proba)

[output] 조기 중단을 적용하지 않을 때보다 약간 저조한 성능을 보이지만 큰 차이는 없다. 하지만 조기 중단 값을 너무 급격하게 줄이면 예측 성능이 저하될 우려가 크다.

# early_stopping_rounds를 10으로 설정하고 재 학습. 
xgb_wrapper.fit(X_train, y_train, 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)

[output] early_stopping_rouns를 10번으로 설정하고 학습한 결과이다. 62번 반복까지만 수행된 후 학습이 종료되었고, 결과 정확도도 낮아진 것을 볼 수 있다.

profile
NLP, AI, LLM, MLops

0개의 댓글