●XGBoost는 트리 기반의 앙상블 학습에서 가장 각광받고 있는 알고리즘 중 하나로 일반적으로 다른 머신러닝보다 뛰어난 예측 성능을 나타낸다.

●XGBoost는 GBM에 기반하고 있지만, GBM의 단점인 느린 수행 시간 및 과적합 규제 기능이 없는 등의 문제를 해결해서 매우 각광을 받고 있다.(GBM에 과적합 규제 기능을 추가한 것)

 

<XGBoost의 장점>

1) 뛰어난 예측 성능

분류와 회귀에서 뛰어난 예측 성능을 발휘

 

2) GBM 대비 빠른 수행 시간

GBM은 순차적으로 weak learner가 가중치를 증감하는 방법으로 학습하기 때문에 전반적으로 속도가 느리다. 하지만 XGBoost는 병렬 수행으로 GBM에 비해 빠른 수행 성능을 보장한다.

XGBoost가 GBM에 비해 수행 시간이 빠르다는 것이지, 다른 머신러닝 알고리즘(예를 들어 랜덤포레스트)에 비해서 빠르다는 의미는 아니다.

 

3) 과적합 규제(Regularization)

GBM의 경우 과적합 규제 기능이 없으나 XGBoost는 자체에 과적합 규제 기능으로 과적합에 좀 더 강한 내구성을 가진다.

 

4) Tree pruning(나무 가지치기)

GBM과 마찬가지로 XGBoost도 max_depth 파라미터로 분할 깊이를 조정하기도 하지만, Tree pruning으로 더 이상 긍정 이득이 없는 분할을 가지치기 해서 분할 수를 더 줄이는 추가적인 장점을 가지고 있다.

 

5) 자체 내장된 교차검증

XGBoost는 반복 수행 시마다 내부적으로 교차검증을 수행해 최적화된 반복 수행 횟수를 가질 수 있다.

→지정된 반복 횟수가 아니라 교차검증을 통해 비용 평가 값이 최적화되면 반복을 중간에 멈출 수 있는 조기 중단 기능이 있다.

 

6) 결측값 자체 처리

XGBoost는 결측값을 자체 처리할 수 있는 기능을 가지고 있다.


<XGBoost 파이썬 구현>

초기의 독자적인 XGBoost 프레임워크 기반의 XGBoost를 파이썬 래퍼 XGBoost 모듈, 사이킷런과 연동되는 모듈을 사이킷런 래퍼 XGBoost 모듈이 존재한다.

 

사이킷런 래퍼 XGBoost 모듈은 사이킷런의 다른 estimator와 사용법이 같은 데 반해 파이썬 래퍼 XGBoost 모듈은 고유의 API와 하이퍼 파라미터를 이용한다.

 

# 파이썬 래퍼 XGBoost 모듈과 사이킷런 래퍼 XGBoost 모듈 API 비교

 

# XGBoost의 하이퍼 파라미터

일반 파라미터

: 일반적으로 실행 시 스레드의 개수나 silent 모드 등의 선택을 위한 파라미터, default값을 바꾸는 일은 거의 없음

부스트 파라미터

: 트리 최적화, 부스팅, regularization 등과 관련된 파라미터를 지칭

학습 태스크 파라미터

: 학습 수행 시의 객체함수, 평가를 위한 지표 등을 설정하는 파라미터


<과적합 문제가 심각할 경우 : 과적합 제어>

●eta 값을 낮춤(0.01 ~ 0.1) → eta 값을 낮출 경우 num_boost_rounds(n_estimators)는 반대로 높여줘야 한다.

●max_depth 값을 낮춤

●min_child_weight 값을 높임

●gamma(min_split_loss) 값을 높임

●sub_sample(subsample), colsample_bytree 값을 낮춤 → 트리가 너무 복잡하게 생성되는 것을 막아 과적합 문제에 도움이 될 수 있음


XGBoost 자체적으로 교차검증, 성능 평가, 피처 중요도 등의 시각화 기능을 가지고 있다. 또한 XGBoost는 GBM에서 부족한 다른 여러 가지 성능 향상 기능이 있다. 그중에 수행 속도를 향상시키기 위한 대표적인 기능으로 조기 중단(Early Stopping) 기능이 있다.

GBM의 경우 num_boost_rounds(n_estimators)에 지정된 횟수만큼 반복적으로 학습 오류를 감소시키며 학습을 진행하면서 중간에 반복을 멈출 수 없고 num_boost_rounds(n_estimators)에 지정된 횟수를 다 완료해야 한다. 하지만 XGBoost, LightGBM은 모두 조기 중단 기능이 있어서 n_estimators에 지정한 부스팅 반복 횟수에 도달하지 않더라도 예측 오류가 더 이상 개선되지 않으면 반복을 끝까지 수행하지 않고 중지해 수행 시간을 개선할 수 있다.

 

<XGBoost 조기 중단 기능(Early Stopping)>

●XGBoost는 특정 반복 횟수 만큼 더 이상 비용함수가 감소하지 않으면 지정된 반복횟수를 다 완료하지 않고 수행을 종료할 수 있음

●학습을 위한 시간을 단축 시킬 수 있음. 특히 최적화 튜닝 단계에서 적절하게 사용 가능

●너무 반복 횟수를 단축할 경우 예측 성능 최적화가 안된 상태에서 학습이 종료 될 수 있으므로 유의 필요

●조기 중단 설정을 위한 주요 파라미터

▷early_stopping_rounds: 더 이상 비용 평가 지표가 감소하지 않는 최대 반복횟수

▷eval_metric: 반복 수행 시 사용하는 비용 평가 지표

▷evals(eval_set): 평가를 수행하는 별도의 검증 데이터 세트. 일반적으로 검증 데이터 세트에서 반복적으로 비용 감소 성능 평가(파이썬 래퍼: evals / 사이킷런 래퍼: eval_set)

 

예를 들어 n_estimators를 200으로 설정하고 조기 중단 파라미터 값을 50으로 설정하면, 1부터 200회까지 부스팅을 반복하다가 50회를 반복하는 동안 학습 오류가 감소하지 않으면 더 이상 부스팅을 진행하지 않고 종료한다.(가령 100회에서 학습 오류 값이 0.8인데, 101~150회 반복하는 동안 예측 오류가 0.8보다 작은 값이 하나도 없으면 부스팅을 종료한다)


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

위스콘신 유방암 데이터 세트는 종양의 크기, 모양 등의 다양한 속성값을 기반으로 악성 종양(malignant)인지 양성 종양(benign)인지를 분류한 데이터 세트이다. 

위스콘신 유방암 데이터 세트에 기반해 종양의 다양한 피처에 따라 악성 종양(malignant)인지 양성 종양(benign)인지를 XGBoost를 이용해 예측해보자!

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()
features = dataset.data
labels = dataset.target

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

# 레이블 분포 확인
print(dataset.target_names)
print(cancer_df['target'].value_counts())

위스콘신 유방암 데이터 세트의 80%를 학습용, 20%를 테스트용으로 추출한 뒤 이 80%의 학습용 데이터에서 90%를 최종 학습용, 10%를 검증용으로 분할한다. 검증용 데이터 세트를 별도로 분할하는 이유는 XGBoost가 제공하는 기능인 검증 성능 평가와 조기 중단(early stopping)을 수행하기 위해서이다.

# 피처와 레이블 구분
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)

전체 569개의 데이터 세트에서 최종 학습용 409개, 검증용 46개, 테스트용 114개가 추출됨

 

파이썬 래퍼 XGBoost만의 전용 데이터 객체인 DMatrix를 사용해야 한다. 때문에 numpy, pandas로 되어 있는 학습, 검증, 테스트용 데이터 세트를 모두 전용의 데이터 객체인 DMatrix로 생성하여 모델에 입력해 줘야 한다. 

(파이썬 래퍼 XGBoost 초기 버전은 주로 넘파이를 입력 파라미터를 받아서 DMatrix를 생성하였지만, 현 버전은 넘파이 외에도 DataFrame, Series 기반으로도 DMatrix를 생성할 수 있음→초기 버전은 판다스의 DataFrame과 호환되지 않아서 DMatrix 생성 시 오류가 발생할 경우 DataFrame.values를 이용해 넘파이로 일차 변환한 뒤에 이를 이용해 Dmatrix 변환을 적용해야 함)

DMatrix의 주요 입력 파라미터는 data와 label로 data는 피처 데이터 세트, label은 분류의 경우 레이블 데이터 세트, 회귀의 경우 숫자형인 종속값 데이터 세트이다.

# 학습, 검증, 테스트용 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)

파이썬 래퍼 XGBoost로 학습을 수행하기 전에 먼저 XGBoost의 하이퍼 파라미터를 딕셔너리 형태로 설정하자.

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

파이썬 래퍼 XGBoost는 하이퍼 파라미터를 xgboost 모듈의 train() 함수에 파라미터로 전달한다.(사이킷런 래퍼 XGBoost의 경우 Estimator의 생성자를 하이퍼 파라미터로 전달)

 

조기 중단(Early Stopping)의 성능 평가는 별도의 검증 데이터 세트를 이용한다. XGBoost는 학습 반복 시마다 검증 데이터 세트를 이용해 성능을 평가할 수 있는 기능을 제공한다. 조기 중단은 xgboost의 train() 함수에 early_stopping_rounds 파라미터를 입력하여 설정한다. 여기서는 조기 중단 할 수 있는 최대 반복 횟수를 50으로 설정하겠다.

 

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

●평가용 데이터 세트는 학습과 평가용 데이터 세트를 명기하는 개별 튜플을 가지는 리스트 형태로 설정. 가령 dtr이 학습용, dval이 평가용이라면 [(dtr, 'train'), (dval, 'evel')]와 같이, 학습용 DMatrix는 'train'으로, 평가용 DMatrix는 'eval'로 개별 튜플에서 명기하여 설정(과거 버전 XGBoost는 위와 같이 학습 데이터 세트와 평가용 데이터 세트를 명기해주어야 했으나 현재 버전은 평가용 데이터 세트만 명기해 줘도 성능 평가를 수행하므로 [(dval, 'eval')]로 설정해도 무방

●eval_metric은 평가 세트에 적용할 평가 지표. 분류일 경우 주로 'error'(분류 오류), 'logloss'를 적용

# 학습 데이터 셋은 'train', 평가 데이터 셋은 'eval'로 명기
eval_list = [(dtr, 'train'), (dval, 'eval')] # eval_list = [(dval, 'eval')]

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
[1]	train-logloss:0.61131	eval-logloss:0.63609
[2]	train-logloss:0.57563	eval-logloss:0.61144
... ... ...
[125]	train-logloss:0.01998	eval-logloss:0.25714
[126]	train-logloss:0.01973	eval-logloss:0.25587
[127]	train-logloss:0.01946	eval-logloss:0.25640
[128]	train-logloss:0.01927	eval-logloss:0.25685
... ... ...
[175]	train-logloss:0.01267	eval-logloss:0.26086
[176]	train-logloss:0.01258	eval-logloss:0.26103

train()으로 학습을 수행하면서 반복 시마다 train-logloss와 eval-logloss가 지속적으로 감소하고 있다. 하지만 num_boost_round를 400회로 설정했음에도 불구하고 학습은 400번을 반복하지 않고 0부터 시작하여 176번째 반복에서 완료했음을 알 수 있다. 출력 결과에서 126번째 반복에서 eval-logloss로 표시되는 검증 데이터에 대한 logloss 값이 0.25587로 가장 낮다. 이후 126번에서 176번까지 early_stopping_rounds로 지정된 50회 동안 logloss 값은 이보다 향상되지 않았기 때문에(logloss가 작을수록 성능이 좋음. 즉, 예측 오류가 작을수록 성능이 좋음) 더 이상 반복하지 않고 멈춘 것이다.

 

xgboost를 이용해 모델의 학습이 완료했으니 이를 이용해 테스트 데이터 세트에 예측을 수행해보자.

한 가지 유의할 점은 사이킷런 래퍼 XGBoost의 predict() 메서드는 예측 결과 클래스 값을 반환하는 데 파이썬 래퍼 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으로 예측값 결정하여 list 객체인 preds에 저장
preds = [1 if x > 0.5 else 0 for x in pred_probs]
print('예측값 10개만 표시:', preds[:10])

XGBoost 모델의 예측 성능을 평가해 보자.

from sklearn.metrics import *

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_score(y_test, pred_proba)
    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, pred_probs)

xgboost 패키지에 내장된 시각화 기능인 plot_importance() API는 피처의 중요도를 시각화해준다.

f스코어는 해당 피처가 트리 분할 시 얼마나 자주 사용되었는지를 지표로 나타낸 값으로, f스코어를 기반으로 해당 피처의 중요도를 나타낸다. (사이킷런은 Estimator 객체의 feature_importances_ 속성을 이용해 직접 시각화 코드를 작성해야 하지만, xgboost 패키지는 plot_importance()를 이용해 바로 피처 중요도를 시각화할 수 있다.) 

 

plot_importance() 호출 시 파라미터로 앞에서 학습이 완료된 모델 객체, 맷플롯립의 ax 객체를 입력한다.

plot_importance() 이용 시 유의할 점은 xgboost를 DataFrame이 아닌 넘파이 기반의 피처 데이터로 학습하면 넘파이에서 피처명을 제대로 알 수가 없으므로 Y축의 피처명을 나열 시 f0, f1과 같이 피처 순서별로 f자 뒤에 순서를 붙여서 피처명을 나타낸다.(f0는 첫 번째 피처, f1은 두 번째 피처)

import matplotlib.pyplot as plt
%matplotlib inline

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


파이썬 래퍼 XGBoost의 교차검증 수행 및 최적 파라미터 구하기

: 사이킷런의 GridSearchCV와 유사하게 교차검증 수행 및 최적 파라미터를 구할 수 있는 cv() API를 제공한다.

xgboost.cv(params, dtrain, num_boost_round=10, nfold=3, stratified=False, folds=None, metrics=(), obj=None, feval=None, maximize=False, early_stopping_rounds=None, fpreproc=None, as_pandas=True, verbose_eval=None, show_stdv=True, seed=0, callbacks=None, shuffle=True)

●params: 부스터 파라미터(딕셔너리 형태)

●dtrain: 학습 데이터(DMatrix 형태)

●num_boost_round: 부스팅 반복 횟수(생성할 약한 학습기 수)

●nfold: cv 폴드 수

●stratified: cv 수행 시 층화 표본 추출 수행 여부(bool 형태, 원본 데이터의 레이블 비율을 활용할것인지)

●metrics: cv 수행 시 모니터링할 성능 평가 지표(string 또는 list of strings 형태)

●early_stopping_rounds: 조기 중단을 활성화시킴. 반복 횟수 지정

 

→xgb.cv의 반환값은 DataFrame 형태

'파이썬 머신러닝 완벽가이드 > [4장] 분류' 카테고리의 다른 글

부스팅 정리  (0) 2023.02.15
XGBoost(eXtra Gradient Boost) (2)  (0) 2023.02.14
부스팅  (0) 2023.02.10
배깅  (0) 2023.02.09
앙상블 학습  (0) 2023.02.09

+ Recent posts