본문 바로가기

Lecture ML

머신러닝 강좌 #18] XGBoost (eXtra Boost Machine)

반응형

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


과적합(overfitting)은 기계 학습(machine learning)에서 학습 데이타를 과하게 학습(overfitting)하는 것을 뜻한다. 일반적으로 학습 데이타는 실제 데이타의 부분 집합이므로 학습데이타에 대해서는 오차가 감소하지만 실제 데이타에 대해서는 오차가 증가하게 된다. (추가내용)

  • 일반적으로 학습 데이타는 실제 데이타의 부분집합이며, 실제 데이타를 모두 수집하는 것은 불가능하다.
  • 만약 실제 데이타를 모두 수집하여도 모든 데이타를 학습 시키기 위한 시간이 측정 불가능한 수준으로 증가 할 수 있다.
  • 학습 데이타만 가지고 실제 데이타의 오차가 증가하는 지점을 예측하는 것은 매우 어렵거나 불가능하다.

XGBoost의 핵심 라이브러리는 C/C++로 작성돼 있습니다. XGBoost개발 그룹은 파이썬에서도 XGBoost를 구동할 수 있도록 파이썬 패키지를 제공합니다. 

 

뛰어난 알고리즘일수록 파라미터를 튜닝할 필요가 적습니다. 그리고 파라미터 튜닝에 들이는 공수 대비 성능 향상 효과가 높지 않은 경우가 대부분입니다. 파라미터를 튜닝하는 경우의 수는 여러 가지 상황에 따라 달라집니다. 피처의 수가 매우 많거나 피처 간 상관되는 정도가 많거나 데이터 세트에 따라 여러 가지 특성이 있을 수 있습니다. 

 

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

  • eta값을 낮춥니다. (0.01 ~ 0.1). eta값을 낮출 경우 num_round(또는 n_estimators)는 반대로 높여줘야 합니다.
  • max_depth값을 낮춥니다.
  • min_child_weight값을 높입니다.
  • gamma값을 높입니다.
  • 또한 subsample과 colsample_bytree를 조정하는 것도 트리가 너무 복잡하게 생성되는 것을 막아 과적합 문제에 도움이 될 수 있습니다.

 

XGBoost는 GBM의 속도 개선을 위해 조기 중단(early stopping) 기능이 있습니다. 기본 GBM의 경우 n_estimator에 지정된 횟수만큼 반복적으로 학습 오류를 감소시키며 학습을 진행하면서 중간에 반복을 멈출 수 없고 n_estimators에 지정된 횟수를 다 완료해야 합니다. 

 

조기 중단 기능은 n_estimator에 지정한 부스팅 반복 횟수에 도달하지 않더라도 예측 오류가 더 이상 개선되지 않으며 반복을 수행하지 않고 중지해 수행 시간을 개선할 수 있습니다.

 

 

 

 

위스콘신 유방암 데이터 세트를 활용하여 파이썬 래퍼 XGBoost API의 사용법을 살펴보겠습니다. XGBoost의 파이썬 패키지인 xgboost는 자체적으로 교차 검증, 성능 평가, 피처 중요도 등의 기능을 가지고 있습니다. 또한 조기 중단 기능이 있어서 num_rounds로 지정한 부스팅 반복 횟수에 도달하지 않더라도 더 이상 예측 오류가 개선되지 않으면 반복을 끝까지 수행하지 않고 중지해 수행 시간을 개선하는 기능도 가지고 있습니다. 

 

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 Common_Module.CMStat as CMStat
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(cancer_df.info())
print(cancer_df['target'].value_counts())

 

XGBoost는 학습용과 테스트용 데이터 세트를 위해 별도의 객체인 DMatrix를 생성한다는 점입니다.

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)

 

XGBoost 모듈인 xgboost를 이용해 학습을 수행하기 전에 먼저 XGBoost의 하이퍼 파라미터를 설정합니다.

  • max_depth: 트리 최대 깊이
  • eta: 학습률
params = {'max_depth' : 3,
          'eta': 0.1,
          'objective':'binary:logistic',
          'eval_metric':'logloss',
          'early_stopping':100
          }
num_rounds = 400

 

조기 중단은 XGBoost가 수행 성능을 개선하기 위해서 더 이상 지표 개선이 없을 경우에 num_boost_round횟수를 모두 채우지 않고 중간에 반복을 빠져 나올 수 있도록 하는 것입니다.

 

조기 중단은 xgboost의 train()함수에 early_stopping_rounds파라미터를 입력하여 설정합니다. 여기서는 조기 중단 할 수 있는 최소 반복 횟수를 100을 설정하겠습니다.

 

early_stopping_rounds파라미터를 설정해 조기 중단을 수행하기 위해서는 반드시 eval_set과 eval_metric이 함께 설정돼야 합니다. Xgboost는 반복마다 eval_set으로 지정된 데이터 세트에서 eval_metrics의 지정된 평가 지표로 예측 오류를 측정합니다.

 

  • eval_set는 성능 평가를 수행할 평가용 이터 세트를 설정.
  • eval_metric은 평가 세트에 적용할 성능 평가 방법, 분류일 경우 주로 'error'(분류 오류), 'logloss'를 적용.

 

evals파라미터에 학습 데이터 세트와 eval데이터 세트를 명기해주면 평가를 eval데이터 세트를 수행하면서 조기 중단을 적용할 수 있습니다. 조기 중단을 수행하려면 반드시 evals파라미터에 eval데이터 세트를 명기해줘야 합니다. 이제 xgboost모듈의 train()함수를 호출하면 학습을 수행합니다. 이때 반복 시마다 evals에 표시된 데이터 세트에 대해 평가 지표 결과가 출력됩니다. 

 

wlist = [(dtrain, 'train'), (dtest, 'eval')]
xgb_model = xgb.train(params=params, dtrain=dtrain, num_boost_round=num_rounds, early_stopping_rounds=100, evals=wlist)

 

train()으로 학습을 수행하면 반복 시 train-error와 eval-logloss가 지속적으로 감소합니다. xgboost를 이용해 모델의 학습이 완료됐으면 이를 이용해 테스트 데이터 세트에 예측을 수행해 보겠습니다. 

[281]	train-logloss:0.00567	eval-logloss:0.08664
[282]	train-logloss:0.00566	eval-logloss:0.08650
[283]	train-logloss:0.00566	eval-logloss:0.08636
[284]	train-logloss:0.00565	eval-logloss:0.08640
....
....
....
[305]	train-logloss:0.00549	eval-logloss:0.08606
[306]	train-logloss:0.00548	eval-logloss:0.08597
[307]	train-logloss:0.00548	eval-logloss:0.08600
[308]	train-logloss:0.00547	eval-logloss:0.08600
[309]	train-logloss:0.00546	eval-logloss:0.08588
[310]	train-logloss:0.00546	eval-logloss:0.08592
[311]	train-logloss:0.00545	eval-logloss:0.08595
Stopping. Best iteration:
[211]	train-logloss:0.00641	eval-logloss:0.08559

 

파이썬 래퍼 XGBoost는 train()함수를 호출해 학습이 완료된 모델 객체를 반환하게 되는데, 이 모델 객체는 예측을 위해 predict()메서드를 이용합니다. 한 가지 유의할 점은 사이킷런의 predict()메서드는 예측 결과 클래스 값(0, 1)을 반환하는 데 반해 xgboost의 predict()는 예측 결괏값이 아닌 예측 결과를 추정할 수 있는 확률 값을 반환한다는 것입니다. 

 

본 예제는 암이 악성인지, 양성인지를 판단하는 이진 분류이므로 예측 확률이 0.5보다 크면 1, 그렇지 않으면 0으로 예측 값을 결정하는 로직을 추가하면 됩니다.

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

#예측 확률이 0.5보다 크며 1, 그렇지 않으면 0으로 예측값 결정해 리스트 객체인 preds에 저장
preds = [1 if x > 0.5 else 0 for x in pred_probs]
print(preds[:10])

 

평가 측정을 해보겠습니다.

CMStat.get_clf_eval(y_test, preds, pred_probs)
오차행렬:
 [[35  2]
 [ 1 76]]

정확도: 0.9737
정밀도: 0.9744
재현율: 0.9870
F1: 0.9806

 

 

 

 

 

xgboost의 plot_importance() API는 피처의 중요도를 막대그래프 형식으로 나타냅니다. 기본 평가 지표로 f1스코어를 기반으로 해 각 피처의 중요도를 나타냅니다. 유의 할 점은 xgboost 넘파이 기반의 피처 데이터로 학습 시에 피처명을 제대로 알 수 가 없으모 f0, f1와 같이 피처 순서별로 f자뒤에 순서를 붙여서 X축에 피처들로 나열합니다.

from xgboost import plot_importance
import matplotlib.pyplot as plt

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

 

tree 구현을 위한 plot_tree도 존재합니다.  https://graphviz.org/download/ 에서 graphviz를 설치해야 합니다.

from xgboost import plot_tree
from matplotlib.pylab import rcParams

##set up the parameters
rcParams['figure.figsize'] = 80,80
plot_tree(xgb_model, num_trees=3)
# xgb.cv(params, dtrain, num_boost_round=400, nfold=3, stratified=False, early_stopping_rounds=100)
plt.show()

 

 

반응형