Search

부스팅 - XGBoost

현재 가장 각광을 받고 있는 그래디언트 부스팅(GBM) 기반 머신러닝 패키지다.
정형데이터에서 신경망보다도 뛰어난 학습속도와 예측 성능에서 모두 뛰어난 성능을 보여준다고 한다.
GBM을 기반으로 하지만 느린 수행 시간과 과적합 규제의 부재 라는 단점을 해결해서 각광을 받고 있다.
또한, 병렬 학습이 가능해 GBM보다 학습이 훨씬 빠르다. 그렇다고 해서 다른 머신러닝 알고리즘에 비해서 빠르다는 얘기는 아니다.
자체에 과적합 규제 기능이 있다.
max_depth 뿐만아니라 tree pruning이라는 가지치기를 통해서 과적합을 규제할 수 있다.
내부적으로 학습 데이터 세트와 평가 데이터 세트에 대한 교차 검증을 수행할 수 있다. 물론, 평가 값이 최적화가 되면 조기 중단할 수 있는 기능도 있다.
결손값을 자체 처리할 수 있는 기능을 가지고 있다.
XGBoost의 파이썬 패키지명은 “xgboost”다. 여기에는 XGBoost 전용 파이썬 패키지와 사이킷런과 호환되는 래퍼용 XGBoost 가 있다.
초기는 XGBoost 전용 파이썬 패키지만 됐었다. 이를 파이썬 래퍼 XGBoost라고 부르겠다.
사이킷런 호환 래퍼용 XGBoost사이킷런 래퍼 XGBoost 모듈(XGBClassifier, XGBRegressor)이라고 부르겠다.
먼저, 파이썬 래퍼 xgboost는 고유의 API와 하이퍼 파라미터를 이용한다.

XGBoost 설치하기

아나콘다를 이용해서 설치하겠다.
1.
아나콘다 관리자 권한 프롬프트에서 conda install -c anaconda py-xgboost 를 입력한다.
2.
설치하겠냐고 물으면 y를 입력한다.
3.
설치 끝
설치가 잘 됐는지 확인한다.
import xgboost as xgb from xgboost import XGBClassifier
Python
복사

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

먼저, XGBoost는 앞의 GBM과 유사한 하이퍼 파라미터를 동일하게 가지고 있다. 단지 조기 중단’, ‘나무 치기’, ‘자체 교차 검증’ 등이 추가된 것일 뿐이다.
먼저, 주의할 점은 파이썬 래퍼 XGBoost 모듈과 사이킷런 래퍼 XGBoost 모듈의 일부 하이퍼 파라미터는 약간 다르다는 것이다.
일단, 파이썬 래퍼 XGBoost 의 하이퍼 파라미터를 알아본 다음 사이킷런 래퍼 XGBoost 의 하이퍼 파라미터를 살펴보겠다.
파이썬 래퍼 XGBoost 의 하이퍼 파라미터의 유형
1.
일반 파라미터 : 어떤 모형을 부스터로 사용할 것인지 설정.
booster
‘gbtree’ : 결정트리 / ‘gblinear’ : 선형 모형 / ‘dart’ : 신경망의 드롭아웃을 적용시킨 방법→ 디폴트 값을 바꾸는 경우는 거의 없다. ( 신경 쓸 필요 x )
verbosity [default = 1] : 0(생략) / 1(경고) / 2(알려줌) / 3(debug)
3.
부스터 파라미터 : 트리 최적화, 부스팅, 규제 등과 관련된 파라미터 등을 지칭한다.
4.
학습 태스크 파라미터 : 학습 수행 시의 객체 함수, 평가를 위한 지표 등을 설정하는 파라미터다.
—> 대부분의 하이퍼 파라미터 조정은 부스터 파라미터를 변형시키는 것이다.
주요 부스터 파라미터
eta(default=0.3) / learning_rate(0.1) : 학습률(0~1) . 파이썬→ eta, 사이킷런 → learning_rate, 일반적으로 0.01~0.2 사이의 값 선호
하이퍼파라미터 튜닝시에는 0.1~0.3 정도의 값을 사용하고, 최종 모형 학습시에는 0.05이하의 값을 사용하는 것이 좋다.
gamma [default=0]: 트리의 리프 노드를 추가적으로 나눌지 결정할 최소 손실 감소 값. 해당 값보다 큰 손실이 감소된 경우 리프 노드를 분리한다. 값이 클수록 과적합 감소 효과가 있고 보수적이다.
max_depth [default=6] : 트리 기반 알고리즘의 max_depth와 같음. 0으로 하면 제한 없음. 일반적으로 3~10 사이의 값 적용
num_boost_rounds / n_estimators : 사용할 학습 분류기의 개수
최종 모형으로 전체 데이터셋을 학습할 때는 cross validation을 early_stopping 과 함께 사용해서 각 폴드별 iteration 수를 구한 다음 그 평균값에 10% 정도 더 큰 값을 사용하는 것이 좋다고 한다. early_stopping_rounds 은 보통 50 정도의 값을 사용한다.
min_child_weight[default=1] : 트리에서 추가적으로 가지를 나눌지를 결정하기 위해 필요한 데이터들의 가중치 총합. 클수록 분할을 자제한다. (과적합 조절 위해)
sub_sample [ default=1 ] : GBM의 subsample과 같다. 과적합되는 것을 제어하기 위해 데이터를 샘플링 하는 비율을 지정. 0.5로 지정하면 데이터의 절반을 사용한다는 의미. 일반적으로 0.5 ~ 1사이의 값을 사용
colsample_bytree [ default=1 ] : GBM의 max_features 와 유사. 마찬가지로 과적합 제어하기 위해 사용. 사용할 피처를 임의로 지정
lambda [ default=1, alias=reg_lambda ] : L2 규제 적용 값. 피처 개수가 많을 경우 적용을 검토, 값이 클수록 과적합 감소 효과 큼
alpha [ default=0, alias=reg_alpha ] : L1 규제 적용 값. 마찬가지로 피처 개수가 많을 경우 적용을 검토, 값이 클수록 과적합 감소 효과 큼
scale_pos_weight [ default=1 ] : 불균형한 레이블로 구성된 데이터 세트의 균형을 유지하기 위한 파라미터. A typical value to consider: sum(negative instances) / sum(positive instances)
max_delta_step[ default=0 ] : 일반적으로 필요한 파라미터는 아니나, booster를 logistic regression 을 사용하고 불균형 레이블인 경우 양수값을 주면 과적합을 많이 방지할 수 있다.
sampling_method[ default = ‘uniform’ ] : 데이터를 샘플링하는 방법을 지정한다.
tree_method : 트리를 만드는 방법을 설정하는 파라미터로 xgboost에만 존재하며, 모델성능과 학습시간에 영향을 준다.
정확한 학습을 위해서는 Exact method('exact'), 학습속도를 높이기 위해서는 Approximate method('approx''hist', 'gpu_hist')를 이용하는 것이 좋다.
‘auto’(default) : 알아서 최적의 방법을 선택해줌
→ 잘 모르겠다면 default 사용하고, 데이터 셋이 많다고 하면 approx, hist, gpu_hist 를 시도해보자.
데이터 행수가 10만 단위가 넘어간다면 xgboost에서는 'gpu_hist'를 쓰는 것이 정신건강에 이롭다. 개인적인 경험에 의하면 10배 이상의 학습시간 차이가 있다고 한다. 데이터 행수가 적다면 정확도를 위해 'exact'를 사용하고, 데이터 행수가 많은데 gpu를 사용할 수 없다면 'hist', gpu를 사용할 수 있다면 'gpu_hist'를 선택하는 것이 좋다.
scale_pos_weight [default=1] : 이진분류면서 레이블이 불균형일 경우 사용.
→ 음성 데이터 수 / 양성 데이터 수 : 전형적인 값
학습 태스크 파라미터
objective [ default = reg:squarederror] : 최솟값을 가져야할 손실 함수 지정. XGBoost는 많은 유형의 손실함수를 사용할 수 있다. 이진분류냐 다중 분류냐에 따라 달라진다.
reg : squarederror : regression with squared loss.
reg : squaredlogerror : regression with squared log loss 12[log(pred+1)log(label+1)]2\frac{1}{2}[log(pred + 1) - log(label + 1)]^2
reg : logistic : logistic regression
binary : logistic : 이진 분류일 때 적용, 확률값을 출력
binary : hinge : hinge loss for binary classification. This makes predictions of 0 or 1, rather than producing probabilities.
multi : softmax : 다중 분류일 때 적용. 이때는 클래스 개수인 num_class 파라미터를 지정해줘야 함.
multi : softprob : multi:softmax와 비슷하지만 반환값이 개별 레이블 클래스의 해당되는 예측 확률이다.
but output a vector of ndata * nclass, which can be further reshaped to ndata * nclassmatrix. The result contains predicted probability of each data point belonging to each class.
eval_metric : 검증에 사용되는 함수. 디폴트는 회귀일 경우 rmse, 분류일 경우는 logloss다.
다음은 그 유형이다.
rmse
mae
logloss : negative log-likelihood
error
merror : multiclass classification error rate
mlogloss : multiclass logloss
auc
주의할 점은 좋은 알고리즘일수록 파라미터를 튜닝할 필요가 적다는 것이다. 파라미터를 튜닝하는 경우는 주로
1.
피처의 수가 매우 많거나
2.
피처간 상관계수가 높거나
과적합 문제가 심각하다면
1.
eta값(학습률)을 낮추면서 num_round 또는 n_estimators를 높여주거나
2.
max_depth 값을 낮추거나
3.
min_child_weight 값을 높이거나
4.
gamma 값(최소 손실 감소 값)을 높이거나
5.
subsample 과 colsample_bytree를 조정하거나
XGBoost는 조기중단의 기능도 있다. 나중에 나올 LightGBM도 마찬가지다. 예측 오류가 더 이상 개선되지 않으면 반복을 끝까지 수행하지 않고 중지해 수행 시간을 개선할 수 있다. 물론 설정해줘야 조기 중단을 수행한다.
XGBoost 버전 확인
import xgboost print(xgboost.__version__) ''' 1.5.0 '''
Python
복사

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

이번에는 파이썬 래퍼 xgboost api 사용법을 알아보겠다. 파이썬 패키지인 xgboost는 자체적으로 교차 검증, 성능 평가, 피처 중요도의 시각화 기능을 가지고 있다. 또한 조기중단 기능도 있다.
하지만, cpu 코어가 많지 않은 개인 컴터에서는 수행시간 향상을 경험하기 힘들 수 있다.
데이터는 앞서 본 것처럼 양성종양인지 악성종양인지 구분하는 데이터다. xgboost모듈을 로딩하고 xgb로 명명하겠다. xgboost패키지는 피처의 중요도를 시각화해주는 plot_importance를 함께 제공한다.
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.head(3)
Python
복사
cancer_df['target']=y_label # cancer_df에 레이블 생성 cancer_df.head(3)
Python
복사
레이블이 어떤 값으로 되어있는지 확인.
print(dataset.target_names) print(cancer_df['target'].value_counts()) ''' ['malignant' 'benign'] 1 357 0 212 Name: target, dtype: int64 ''' # 0이 음성, 1이 양성으로 되어 있다. 분포는 비대칭적으로 보이지는 않는다.
Python
복사
이제, 데이터를 학습 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) ''' (455, 30) (114, 30) '''
Python
복사
파이썬 래퍼 XGBoost는 사이킷런과 다르게 학습용과 테스트용 데이터 세트를 위해 별도의 객체인 DMatrix를 생성한다.
DMatrix는 주로 넘파이를 입력으로 받아서 만들어지는 XGBoost만의 전용 데이터 세트다. 주요 입력 파라미터는 data와 label이다. data는 피처 데이터 세트, label은 분류일 경우에는 레이블 데이터세트, 회귀인 경우에는 숫자형인 종속값 데이터 세트다.
물론 넘파이 외에 libsvm txt 포맷 파일, xgboost 이진 버퍼 파일을 파라미터로 입력받아 변환할 수도 있다.
일단, 판다스의 데이터프레임을 넘파이로 변환하기 위해서는 DataFrame.values를 이용해 넘파이로 변환한 뒤에 이를 이용해 DMatrix 변환을 적용한다.
한번 예제에 적용해보겠다.
# train_test_split의 반환값은 모두 numpy array이므로 dtrain = xgb.DMatrix(data=X_train,label=y_train) dtest = xgb.DMatrix(data=X_test,label=y_test)
Python
복사
이제, 학습 하기 전에 하이퍼 파라미터를 설정해준다. XGBoost의 하이퍼파라미터는 주로 딕셔너리 형태로 입력한다.
다음과 같이 설정할 것이다.
max_depth 는 3
eta는 0.1
이진분류이므로 객체 함수(objective)는 binary:logistic 으로 설정
오류 함수의 평가 성능 지표는 logloss
num_rounds(=n_estimators) 는 400 으로 설정
params={'max_depth':3,'eta':0.1, 'objective':'binary:logistic', 'eval_metric':'logloss', 'early_stopping':100} num_rounds = 400
Python
복사
파이썬 래퍼 XGBoost는 하이퍼 파라미터를 xgboost 모듈의 train() 함수에 파라미터로 전달한다. 사이킷런의 경우는 추정기의 생성자를 하이퍼 파라미터로 전달하는데 반해 차이가 있다.
조기중단train()함수 early_stopping_rounds 파라미터를 입력해주면 된다.
이 예제에서는 조기 중단을 100으로 설정해준다.
그리고, 당연히 조기중단을 하려면 평가 데이터셋과 측정지표를 지정해줘야 한다.
eval_seteval_metric 으로 지정해주면 된다.
eval_set은 evals라는 파라미터에서 학습 데이터 세트와 함께 지정해주면 된다.
# train 데이터 세트는 'train', evaluation(test) 데이터 세트는 'eval'로 명기합니다. wlist = [(dtrain, 'train'), (dtest, 'test')] # 데이터세트 명기 # 하이퍼 파라미터와 early stopping 파라미터를 train() 함수의 파라미터로 전달 xgb_model = xgb.train(params=params, dtrain=dtrain, num_boost_round=num_rounds, early_stopping_rounds=100, evals=wlist)
Python
복사
테스트 데이터 세트에 예측을 수행할 때 predict() 메서드를 사용하는데, 사이킷런의 predict() 메서드는 예측 결과 클래스값(0또는1) 을 반환하는데 반해 얘는 예측 확률값을 반환한다.
이때, 기준값을 0.5로 잡고, 기준값보다 크면 양성, 작으면 음성으로 결정하는 로직을 추가해주면 된다.
pred_probs = xgb_model.predict(dtest) print('predict() 수행 결괏값을 10개만 표시, 예측 확률값으로 표시됨') print(np.round(pred_probs[:10],3)) ''' predict() 수행 결괏값을 10개만 표시, 예측 확률값으로 표시됨 [0.934 0.003 0.91 0.094 0.993 1. 1. 0.999 0.997 0. ] ''' # 예측 확률이 0.5보다 크면 1, 그렇지 않으면 0으로 예측값 결정해 리스트 객체인 preds로 저장 preds = [1 if x > 0.5 else 0 for x in pred_probs] print('예측값 10개만 표시:', preds[:10]) ''' 예측값 10개만 표시: [1, 0, 1, 0, 1, 1, 1, 1, 1, 0] '''
Python
복사
앞서 get_clf_eval() 함수를 적용해서 이 모델의 예측 성능을 평가해보자.
from sklearn.metrics import roc_auc_score,accuracy_score, precision_score, recall_score, confusion_matrix, f1_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) ''' 오차 행렬 [[35 2] [ 1 76]] 정확도:0.9737, 정밀도:0.9744, 재현율:0.9870, f1 스코어:0.9806, AUC : 0.9951 '''
Python
복사
xgboost 패키지에 내장된 시각화 기능을 수행해보자. plot_importance() API는 피처의 중요도를 막대그래프 형식으로 나타낸다. 이때 평가지표는 f1score를 기반으로 한다.
사이킷런은 추정기 객체의 feature_importances_속성을 이용해서 직접 시각화 코드를 짜줘야 했지만 xgboost 패키지는 바로 시각화할 수 있는 것이다.
plot_importance() 의 파라미터학습이 완료된 모델 객체맷플롯립의 ax객체를 입력해주면 된다.
이때 유의할 점은 넘파이 기반의 피처 데이터로 학습 시에 피처명을 제대로 알 수가 없으므로 f0,f1과 같이 피처 순서별로 f자 뒤에 순서를 붙여서 x축에 피처들로 나열한다.
from xgboost import plot_importance import matplotlib.pyplot as plt %matplotlib inline fig, ax = plt.subplots(figsize=(10,12)) plot_importance(xgb_model,ax=ax)
Python
복사
물론, 트리 기반 규칙 구조도 xgboost에서 시각화할 수 있다. to_graphviz() API를 이용하면 주피터 노트북에 바로 규칙 트리 구조를 그릴 수 있다. 물론, Graphviz 프로그램과 패 키지가 설치되어 있어야 사용할 수 있지만.
to_graphviz()의 파라미터는 학습이 완료된 모델 객체Graphviz가 참조할 파일명을 입력해줘야 한다.
데이터세트에 대한 교차 검증을 수행하고 최적 파라미터를 구하는 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 (dict) : 부스터 파라미터
dtrain ( DMatrix ) : 학습 데이터
num_boost_round (int) : 부스팅 반복 횟수
nfold (int) : cv 폴드 개수
stratified (bool) : cv 수행 시 층화 표본 추출 수행 여부
metrics (string or list of strings) : cv 수행 시 모니터링할 성능 평가 지표
early_stopping_rounds (int) : 조기 중단 최소 횟수 지정
xgboost.cv의 반환값은 데이터프레임 형태다.
하지만, 실제로는 편리상의 이유로 사이킷런 래퍼 XGBoost 모듈을 더 많이 쓴다. 앞으로 모든 예제 코드에는 사이킷런 래퍼 XGBoost를 사용하겠다.

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

분류를 위한 래퍼 클래스는 XGBClassifier, 회귀를 위한 래퍼 클래스는 XGBRegressor다.
XGBClassifier는 파이썬 래퍼 클래스에서 사용하던 하이퍼파라미터를 다음과 같이 변경한다.
eta → learning_rate
sub_sample → subsample
lambda → reg_lambda (L2 규제)
alpha → reg_alpha(L1 규제)
num_boost_round → n_estimators
이제, 유방암 데이터세트에 대해 XGBClassifier을 이용해 예측을 해 보겠다.
앞의 파이썬 래퍼 XGBoost 와 동일하게 하이퍼 파라미터를 사용하겠다.
n_estimators = 400
learning_rate = 0.1
max_depth = 3
# 사이킷런 래퍼 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 = wgb_wrapper.predict_proba(X_test)[:,1]
Python
복사
이제 앞의 함수 get_clf_eval() 함수를 통해서 예측 성능 평가를 해보겠다.
get_clf_eval(y_test,w_preds,w_pred_proba) ''' 오차 행렬 [[35 2] [ 1 76]] 정확도:0.9737, 정밀도:0.9744, 재현율:0.9870, f1 스코어:0.9806, AUC : 0.9951 '''
Python
복사

xgbclassifier의 조기중단

물론, 사이킷런 래퍼 XGBClassifier도 조기 중단을 수행할 수 있다. fit()에 입력하면 된다.
다음의 파라미터들이 추가적으로 필요하다.
early_stopping_rounds : 최소 반복 횟수
eval_metric : 조기 중단에 사용하는 평가 지표
eval_sets : 성능 평가를 수행할 데이터 세트
일단, early_stopping_rounds를 100, eval_metric을 logloss, 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]
Plain Text
복사
이제, 조기 중단으로 학습된 XGBClassifier의 예측 성능을 알아보자. 물론, 조기 중단이 적용되지 않은 결과보다는 약간 안좋을 것이지만 중요하지 않다.
get_clf_eval(y_test,ws100_preds,ws100_pred_proba) ''' 오차 행렬 [[34 3] [ 1 76]] 정확도:0.9649, 정밀도:0.9620, 재현율:0.9870, f1 스코어:0.9744, AUC : 0.9954 '''
Python
복사
물론, 조기 중단값을 너무 작은 값으로 작으면 문제가 생긴다. 성능이 향상될 가능성을 아예 발견하지 못하기 때문이다. 한번 early_stopping_rounds=10으로 설정하고 예측 성능을 측정해보자.
# 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) ''' 오차 행렬 [[34 3] [ 2 75]] 정확도:0.9561, 정밀도:0.9615, 재현율:0.9740, f1 스코어:0.9677, AUC : 0.9947 '''
Python
복사
확인해보면, early_stopping_rounds가 100일때보다 정확도가 0.9561로 좀 더 낮은 것을 확인할 수 있다.
이제 plot_importance() API에 사이킷런 래퍼 클래스를 입력해서 피처의 시각화 결과를 도출해보자.
from xgboost import plot_importance import matplotlib.pyplot as plt %matplotlib inline fig, ax = plt.subplots(figsize=(10,12)) # 사이킷런 wrapper 클래스를 입력해도 무방 plot_importance(xgb_wrapper,ax=ax)
Python
복사
 xgboost 하이퍼 파라미터 튜닝에 대한 guidebook
가이드북