XGBoost란?

트리 기반의 앙상블 학습에서 가장 각광받고 있는 알고리즘 중 하나로, 캐글(kaggle) 등 경연 대회에서 입상한 많은 데이터 사이언티스트들이 XGboost를 사용하면서 널리 알려지게 되었습니다. 대체로 분류에 있어서 뛰어난 예측 성능을 보이는 특징을 가지고 있습니다.

 

XGboost는 GBM에 기반하고 있는데요. GBM보다 빠르게 학습이 가능하고 오버핏팅 규제 부재 문제 등을 해결한다는 장점이 있다고 합니다. 그 밖에도 Tree pruning이 가능하여 더 이상 긍정 이득이 없는 분할을 가지치기 해서 분할 수를 더 줄이는 추가적인 장점, 자체 내장된 교차 검증 기능, 결손값을 자체 처리할 수 있는 기능 등의 장점도 가지고 있습니다.

 

XGBoost API 학습을 위해 위스콘신 유방암 데이터로 실습을 진행해 본 결과를 정리하여 공유하고자 합니다 :-)

 

 

 

sklearn dataset 위스콘신 유방암 데이터 불러오기

sklearn의 자체 내장 데이터인 load_breast_cancer을 불러오겠습니다.

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.head(3)

cancer_df['target'] = labels
cancer_df.head(3)

 

데이터프레임 마지막에 target 컬럼을 추가하여 각 row의 label을 0 또는 1로 나타냈습니다.

dataset.target_names
# array(['malignant', 'benign'], dtype='<U9')

cancer_df['target'].value_counts()
# target
# 1    357
# 0    212
# Name: count, dtype: int64

 

label이 무엇이 있는지 확인해 보니, 0은 malignanat, 1은 benign임을 확인할 수 있었고, 각각 212개와 357개가 있는 것을 확인할 수 있었습니다.

 

 

train, valid, test 데이터셋 나누기

X_features = cancer_df.iloc[:, :-1]
y_label = cancer_df.iloc[:, -1]

 

먼저 target 컬럼을 제거한 X_feature 데이터프레임, target 컬럼만 떼어낸 y_label 데이터프레임을 생성합니다.

# 8:2 비율로 train:test 나누기
X_train, X_test, y_train, y_test = train_test_split(X_features, y_label, 
                                                    test_size = 0.2, 
                                                    random_state = 156)
                                                    
# 9:1 비율로 다시 train:valid 나누기
X_tr, X_val, y_tr, y_val = train_test_split(X_train, y_train, 
                                            test_size = 0.1, 
                                            random_state = 156)

 

train_test_split() 메소드를 이용하여 8:2 비율로 train:test 데이터셋을 나누고,

나누어진 train은 다시 한 번 9:1 비율로 train:valid으로 나누었습니다.

len(X_tr), len(X_val), len(y_tr), len(y_val), len(X_test), len(y_test)
# (409, 46, 409, 46, 114, 114)

X_tr.shape, y_tr.shape
# ((409, 30), (409,))

 

train, valid, test 데이터의 개수와 shape 등을 확인해 보았습니다.

 

 

 

DMatrix

파이썬 래퍼 XGBoost는 전용 데이터 객체인 DMatrix를 사용합니다. DMatrix의 주요 입력 파라미터는 data와 label입니다.

  • data : 피처 데이터 세트
  • label : (분류) 레이블 데이터 세트 / (회귀) 숫자형인 종속값 데이터 세트
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)

 

 

Hyperparameter

딕셔너리 형태로 하이퍼 파라미터를 설정합니다.

params = {
    'max_depth' : 3,  # 트리의 최대 깊이는 3
    'eta' : 0.05,     # 학습률 0.05
    'objective' : 'binary:logistic',
    'eval_metric' : 'logloss'
}

num_rounds = 400       # 부스팅 반복 횟수는 400회

 

 

XGBoost 모델 학습

  • early_stopping_rounds : 더이상 지표 개선이 없을 경우에 횟수를 모두 채우지 않고 중간에 반복을 빠져 나올 수 있도록 하는 탈출 도구 (조기 중단, 얼리스탑핑)
  • evals : 평가용 데이터 세트, [(학습튜플), (평가튜플)] 형태 - 반복마다 지정된 평가용 데이터 세트에서 eval_metric의 지정된 평가 지표로 예측 오류를 측정 
xgb_model = xgb.train(params = params,
                      dtrain = dtr,
                      num_boost_round = num_rounds,
                      early_stopping_rounds = 50, # 50번째부터 얼리스탑핑 가능
                      evals = [(dtr,'train'), (dval,'eval')])

400회를 다 채우지 못하고 250회에서 중단되었습니다

 

예측 수행

predict() 메소드를 이용해서 test 데이터의 결과를 예측해 보겠습니다.

pred_probs = xgb_model.predict(dtest)

 

예측한 결과를 다양하게 살펴봅시다. (초반 10개값만 봅시다.)

pred_probs[:10]
# array([9.3829882e-01, 3.6695320e-03, 7.5020140e-01, 4.9393266e-02,
#        9.8045909e-01, 9.9958366e-01, 9.9899417e-01, 9.9919862e-01,
#        9.9767953e-01, 5.2314228e-04], dtype=float32)

 

어떤 값인지 한 눈에 보이지 않으므로 np.round()를 이용해서 살펴보겠습니다.

np.round(pred_probs[:10])
# array([1., 0., 1., 0., 1., 1., 1., 1., 1., 0.], dtype=float32)
# 일의 자리까지 반올림

np.round(pred_probs[:10], 3)
# array([0.938, 0.004, 0.75 , 0.049, 0.98 , 1.   , 0.999, 0.999, 0.998,
#       0.001], dtype=float32)
# 소수 셋째 자리까지 반올림

 

반올림을 해서 보니까 예측한 값이 0과 1 사이의 값으로 도출되었음을 확인할 수 있었습니다. 

이제 예측 확률이 0.5보다 크면 1, 그렇지 않으면 0으로 최종 예측값을 결정하여 preds 리스트에 저장하겠습니다.

preds = [1 if x > 0.5 else 0 for x in pred_probs]
preds[:10]
# [1, 0, 1, 0, 1, 1, 1, 1, 1, 0]

 

 

get_clf_eval() 함수

모델을 평가할 수 있는 함수를 작성해 보겠습니다.

from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix, 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_score(y_test, pred_proba)
    print('Confusion Matrix')
    print(confusion)
    print(f'accuracy : {accuracy}, precision : {precision:.4f}, recall : {recall:.4f}')
    print(f'f1 : {f1}, roc_auc : {roc_auc}')
get_clf_eval(y_test, preds, pred_probs)

  • 정확도 accuracy 약 0.96
  • 정밀도 precision 약 0.97
  • 재현율 recall 약 0.97
  • F1-스코어 0.97
  • ROC-AUC 약 0.99

평가 지표가 굉장히 좋네요 :-)

 

 

XGBoost 내장 시각화 기능 수행하기

XGBoost의 plot_importance() API피처의 중요도를 막대그래프 형식으로 나타냅니다.

  • 기본 평가 지표로 f스코어를 기반으로 해당 피처의 중요도를 나타냅니다.
  • f스코어는 해당 피처가 트리 분할 시 얼마나 자주 사용되었는지를 지표로 나타낸 값입니다.
  • xgboost 패키지는 plot_importance()를 이용해 바로 피처 중요도를 시각화할 수 있습니다.
  • plot_importance() 호출 시 파라미터로 앞에서 학습이 완료된 모델 객체 및 matplotlib의 ax 객체를 입력하면 됩니다.
import matplotlib.pyplot as plt
%matplotlib inline

fix, ax = plt.subplots(figsize = (10, 12))
plot_importance(xgb_model, ax = ax)
plt.tight_layout()
plt.savefig('plot.png')

 

 

 

여기까지 XGBoost API 실습 포스팅이었습니다 :-)

감사합니다.

+ Recent posts