06. XGBoost(eXtra Gradient Boost)
XGBoost
- XGBoost는 트리 기반의 앙상블 학습에서 각광받고 있는 알고리즘 중 하나
- GBM에 기반하고 있지만, GBM의 단점인 느린 수행 시간 및 과적합 규제 부재 등의 문제 해결 가능
- CPU 환경에서 병렬학습이 가능해서 기존 GBM보다 빠르게 학습 완료 가능
[주요 장점]
1. 뛰어난 예측 성능
2. GBM 대비 빠른 수행시간
3. 과적합 규제
4. Tree pruning : 더 이상 긍정 이득이 없는 분할을 가지치기 해서 분할 수를 더 줄임
5. 자체 내장된 교차 검증 : 지정된 반복 횟수가 아니라 교차 검증을 통해 평가 데이터셋의 평가값이
최적화 되면 반복을 중간에 멈출 수 있는 조기 중단 기능이 있음
6. 결손값 자체 처리
- XGBoost 프레임워크 기반의 XGBoost을 파이썬 래퍼 XGBoost 모듈
- 사이킷런과 연동되는 모듈을 사이킷런 래퍼 XGBoost 모듈
파이썬 래퍼 XGBoost 의 하이퍼 파라미터
- 일반 파라미터 : 일반적으로 실행 시 스레드의 개수나 silent 모드 등의 선택을 위한 파라미터로서 디폴트 파라미터 값을 바꾸는 경우는 거의 없음
- 부스터 파라미터 : 트리 최적화, 부스팅, regularization 등과 관련 파라미터 등을 지칭함
- 학습 테스크 파라미터 : 학습 수행 시의 객체 함수, 평가를 위한 지표 등을 설정하는 파라미터
XGBoost는 지정한 부스팅 반복 횟수에 도달하지 않더라도 예측 오류가 더이상 개선되지 않으면 반복을 끝까지 수행하지 않고 중지함
파이썬 래퍼 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()
X_features= dataset.data
y_label = dataset.target
cancer_df = pd.DataFrame(data=X_features, columns=dataset.feature_names)
cancer_df['target']= y_label
cancer_df.head(3)
print(dataset.target_names)
print(cancer_df['target'].value_counts())
['malignant' 'benign']
1 357
0 212
Name: target, dtype: int64
# cancer_df에서 feature용 DataFrame과 Label용 Series 객체 추출
# 맨 마지막 칼럼이 Label임. Feature용 DataFrame은 cancer_df의 첫번째 칼럼에서 맨 마지막 두번째 칼럼까지를 :-1 슬라이싱으로 추출.
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%는 검증용 데이터로 분리
# 검증용 데이터셋을 분리하는 이유는 XGBoost가 제공하는 기능인 검증 성능 평가와 조기 중단 수행위함
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)
(455, 30) (114, 30)
(409, 30) (46, 30)
* 파이썬 래퍼 xgboost이 사이킷런과 다른점 : xgboost 만의 전용 데이터 객체인 DMatrix를 사용한다는 점
- 넘파이 외에도 데이터프레임과 시리즈 기반으로도 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의 하이퍼 파라미터 설정
# 주로 딕셔너리 형태로 입력
params = { 'max_depth':3, #최대깊이 : 3
'eta': 0.05, # 학습률 eta=0.1
'objective':'binary:logistic',# 예제 데이터가 0또는1 이진 분류이므로 목적함수(objective)는 이진 로지스틱
'eval_metric':'logloss' # 오류 함수의 평가 성능 지표는 logloss
}
num_rounds = 400 #부스팅 반복횟수
파이썬 래퍼 xgboost는 하이퍼 파라미터를 xgboost 모듈의 train()함수에 파라미터로 전달
조기 중단 기능 제공
- xgboost의 train() 함수에 early_stopping_rounds 파라미터 입력
- 조기 중단 성능 평가는 주로 별도의 검증 데이터셋 사용
- xgboost 는 학습 반복 시마다 검증 데이터셋을 이용해 성능을 평가할 수 있는 기능 제공
- early_stopping_rounds 파라미터를 설정해 조기 중간을 수행하기 위해서는 반드시 평가용 데이터셋 지정과 eval_matric을 함께 설정해야함
- xgboost는 반복마다 지정된 평가용 데이터셋에서 eval_metric의 지정된 평가 지표로 예측 오류를 측정
# 학습 데이터 셋은 'train' 또는 평가 데이터 셋은 'eval' 로 명기합니다.
eval_list = [(dtr,'train'),(dval,'eval')] # 또는 eval_list = [(dval,'eval')] 만 명기해도 무방.
# 하이퍼 파라미터와 early stopping 파라미터를 train( ) 함수의 파라미터로 전달
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
.
.
.
[173] train-logloss:0.01285 eval-logloss:0.26253
[174] train-logloss:0.01278 eval-logloss:0.26229
[175] train-logloss:0.01267 eval-logloss:0.26086
500번 반복하지 않고 176번째 반복에서 완료함
# XGBoost를 이용해 모델의 학습이 완료되면 이를 이용해 테스트 데이터셋에 예측 수행
XGBoost는 train() 함수를 호출해 학습이 완료된 모델 객체 반환 : predict() 사용
사이킷런의 predict() 메서드는 예측 결과 클래스 값 (0,1)을 반환하지만,
xgboost의 predict()는 예측 결과를 추정할 수 있는 확률 값 반환
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])
predict( ) 수행 결과값을 10개만 표시, 예측 확률 값으로 표시됨
[0.845 0.008 0.68 0.081 0.975 0.999 0.998 0.998 0.996 0.001]
예측값 10개만 표시: [1, 0, 1, 0, 1, 1, 1, 1, 1, 0]
# get_clf_eval 로 오차행렬, 정확도, 정밀도, 재현율, F1스코어 구하기
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)
오차 행렬
[[34 3]
[ 2 75]]
정확도: 0.9561, 정밀도: 0.9615, 재현율: 0.9740, F1: 0.9677, AUC:0.9937
# 피처 중요도 시각화하기
- xgboost 패키지에 내장된 시각화 기능 수행 : plot_importance()
- f스코어는 해당 피처가 트리 분할 시 얼마나 자주 사용되었는지 지표로 나타낸 값
- 이용시 유의할 점은 xgboost를 DataFrame이 아닌 넘파이 기반의 피처 데이터로 학습 시
- 넘파이에서 피처명을 제대로 알 수가 없으므로 y축의 피처명을 나열시 f0, f1과 같이 숫자 붙여 나타냄
import matplotlib.pyplot as plt
%matplotlib inline
fig, ax = plt.subplots(figsize=(10, 12))
plot_importance(xgb_model, ax=ax)
plt.savefig('p239_xgb_feature_importance.tif', format='tif', dpi=300, bbox_inches='tight')
사이킷런 래퍼 XGBoost
- 사이킷런의 기본 Estimator를 그대로 상속해 만들었기 때문에 다른 Estimator와 동일하게 fit()과 predict()만으로 학습과 예측이 가능함
- GridSearchCV, pipeline 등 사이킷런의 다른 유틸리티를 그대로 사용할 수 있기 때문에 기존의 다른 머신러닝 알고리즘으로 만들어놓은 프로그램이 있더라도 알고리즘 클래스만 xgboost로 바꿔주면 사용 가능해짐
- 두가지 유형
- 분류를 위한 래퍼 클래스인 XGBClassifier
- 회귀를 위한 래퍼 클래스인 XGBRegressor - 사이킷런의 하이퍼 파라미터와 호환성 유지를 위해 기존 xgboost에서 사용하던 네이티브 하이퍼 파라미터 변경함
eta -> learning_rate
sub_sample -> subsample
lambda -> reg_lambda
alpha -> reg_alpha
# 위스콘신 유방암 데이터셋 분류를 XGBClassifier를 이용해 예측
# 사이킷런 래퍼 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)
오차 행렬
[[35 2]
[ 1 76]]
정확도: 0.9737, 정밀도: 0.9744, 재현율: 0.9870, F1: 0.9806, AUC:0.9951
# 조기중단 수행해보기
[조기 중단 관련 파라미터]
- 평가 지표가 향상될 수 잇는 반복 횟수를 정의하는 early_stopping_rounds : 100
- 조기 중단을 위한 평가 지표인 eval_metric : logloss
- 성능 평가를 수행할 데이터 셋인 *eval_set
(*eval_set : 파이썬 래퍼일 때와 다르게 학습과 검증을 의미하는 문자열을 넣어주지 않아도 됨)
- [(X_tr,y_tr),(X_val,y_val)] 와 같이 지정하면 맨 앞의 튜플이 학승용 데이터, 뒤의 튜플이 검증용 데이터로 자동 인식
from xgboost import XGBClassifier
xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.05, max_depth=3)
evals = [(X_tr,y_tr),(X_val,y_val)]
xgb_wrapper.fit(X_tr, y_tr, early_stopping_rounds=50, 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]
[0] validation_0-logloss:0.65016 validation_1-logloss:0.66183
[1] validation_0-logloss:0.61131 validation_1-logloss:0.63609
[2] validation_0-logloss:0.57563 validation_1-logloss:0.61144
.
.
.
[174] validation_0-logloss:0.01278 validation_1-logloss:0.26229
[175] validation_0-logloss:0.01267 validation_1-logloss:0.26086
[176] validation_0-logloss:0.01258 validation_1-logloss:0.26103
# 평가지표 산출
get_clf_eval(y_test , ws100_preds, ws100_pred_proba)
오차 행렬
[[34 3]
[ 2 75]]
정확도: 0.9561, 정밀도: 0.9615, 재현율: 0.9740, F1: 0.9677, AUC:0.9933
07. lightGBM
lightGBM
- lightGBM은 XGBoost와 함께 부스팅 계열 알고리즘에서 가장 각광 받음
- 시간이 짧게 걸림, 메모리 사용량도 상대적으로 적음
- 예측 성능에는 다른것들과 크게 다르지 않음
- 카테고리형 피처의 자동 변화과 최적 분할(원-핫 인코딩 등을 사용하지 않고도 카테고리형 피처를 최적으로 변환하고 이에 따른 노드 분할 수행)
- 단점은 적은 데이터셋(일반적으로 10,000건 이하)에 적용할 경우 과적합이 발생하기 쉬움
- LightGBM은 일반 GBM 계열의 트리 분할 방법과 다르게 리프 중심 트리 분할(Leaf wise) 방식 사용
- 기존의 대부분 트리 기반 알고리즘은 트리 깊이를 효과적으로 줄이기 위한 균형 트리 분할(Level wise)
- 최대한 균형 잡한 트리를 유지하면서 분할하기 때문에 트리의 깊이가 최소화 될수있기 때문
- 오버피팅에 보다 더 강한 구조를 가질 수 있다고 알려져 있음
- 반대로 균형을 맞추기 위한 시간이 필요하기는 함 - LightGBM의 리프 중심 트리 분할 방식은 트리의 균형을 맞추지 않고,
최대 손실 값(max delta loss)을 가지는 리프 노드를 지속적으로 분할하면서 트리의 깊이가 깊어지고 비대칭적 구조 가짐
-> 이렇게 최대 손실값을 가지는 리프 노드를 지속적으로 분할해 생성된 규칙 트리는 학습을 반복할수록 결국은 균형 트리 분할 방식보다 예측 오류 손실을 최소화할 수 있음
lightGBM 하이퍼 파라미터
xgboost와 비슷하지만 리프 노드가 계속 분할되면서 트리의 깊이가 깊어지므로 이러한 트리 특성에 맞는 하이퍼 파라미터 설정이 필요 (ex. max_depth를 매우 크게 가짐)
하이퍼 파라미터 튜닝 방안
- num_leaves의 개수를 중심으로 min_child_samples(min_data_in_leaf), max_depth를 함께 조정하면서 모델의 복잡도를 줄이는 것이 기본 튜닝 방안
- num_leaves는 개별 트리가 가질 수 있는 최대 리프의 개수이고 lightGBM 모델의 복잡도를 제어하는 주요 파라미터임
- 일반적으로 mun_leaves의 개수를 높이면 정확도가 높아지ㅣㅈ만, 반대로 트리의 깊이가 깊어지고 모델이 복잡도가 커져 과적합 영향도가 커짐
- min_data_in_leaf 는 사이킷런 래퍼 클래스에서는 min_child_samples로 이름이 바뀜
- 과적합을 개선하기 위한 중요한 파라미터임, 보통 큰 값으로 설정하면 트리가 깊어지는 것을 방지해줌
- max_depth는 명시적으로 깊이의 크기를 제한함, 위 파라미터들과 결합하여 과적합을 개선하는데 사용
- learning_rate 를 작게 하면서 n_estimators를 크게 하는 것은 부스팅 계열 튜닝에서 가장 기본적인 튜닝
- n_estimators를 너무 크게 하면 과적합 발생할 수 있음
- 과적합을 제어하기 위해 reg_lambda, reg_alpha와 같은 regularization을 적용하거나 학습 데이터에 사용할 피처의 개수나 데이터 샘플링 레코드 개수를 줄이기 위해 colsample_bytree, subsample 파라미터 적용 가능
LightGBM 적용 - 위스콘신 유방암 예측
# LightGBM의 파이썬 패키지인 lightgbm에서 LGBMClassifier 임포트
from lightgbm import LGBMClassifier
import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
dataset = load_breast_cancer()
cancer_df = pd.DataFrame(data=dataset.data, columns=dataset.feature_names)
cancer_df['target']= dataset.target
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 )
# 앞서 XGBoost와 동일하게 n_estimators는 400 설정.
lgbm_wrapper = LGBMClassifier(n_estimators=400, learning_rate=0.05)
# LightGBM도 XGBoost와 동일하게 조기 중단 수행 가능.
evals = [(X_tr, y_tr), (X_val, y_val)]
lgbm_wrapper.fit(X_tr, y_tr, early_stopping_rounds=50, eval_metric="logloss", eval_set=evals, verbose=True)
preds = lgbm_wrapper.predict(X_test)
pred_proba = lgbm_wrapper.predict_proba(X_test)[:, 1]
Early stopping, best iteration is:
[61] training's binary_logloss: 0.0532381 valid_1's binary_logloss: 0.260236
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_proba)
오차 행렬
[[34 3]
[ 2 75]]
정확도: 0.9561, 정밀도: 0.9615, 재현율: 0.9740, F1: 0.9677, AUC:0.9877
# plot_importance( )를 이용하여 feature 중요도 시각화
from lightgbm import plot_importance
import matplotlib.pyplot as plt
%matplotlib inline
fig, ax = plt.subplots(figsize=(10, 12))
plot_importance(lgbm_wrapper, ax=ax)
plt.savefig('lightgbm_feature_importance.tif', format='tif', dpi=300, bbox_inches='tight')
'머신러닝' 카테고리의 다른 글
Machine Learning (0) | 2024.04.20 |
---|---|
ML_Overview (0) | 2024.04.14 |
[4장] 파이썬 머신러닝 완벽 가이드_분류_2 (1) | 2023.05.24 |
[4장] 파이썬 머신러닝 완벽 가이드_분류_1 (0) | 2023.05.20 |
[3장] 파이썬 머신러닝 완벽 가이드_평가_2 (0) | 2023.05.13 |