[Python] 머신러닝 완벽가이드 - 04. 분류[LightGBM]
Updated:
파이썬 머신러닝 완벽가이드 교재를 토대로 공부한 내용입니다.
실습과정에서 필요에 따라 내용의 누락 및 추가, 수정사항이 있습니다.
기본 세팅
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
mpl.rc('font', family='NanumGothic') # 폰트 설정
mpl.rc('axes', unicode_minus=False) # 유니코드에서 음수 부호 설정
# 차트 스타일 설정
sns.set(font="NanumGothic", rc={"axes.unicode_minus":False}, style='darkgrid')
plt.rc("figure", figsize=(10,8))
warnings.filterwarnings("ignore")
1. LightGBM
LightGBM 장단점
-
XGB보다도 학습에 걸리는 시간이 훨씬 적으며 메모리 사용량도 상대적으로 적다.
-
카테고리형 피처를 자동 변환하고, 예측 성능 역시 큰 차이가 없다.
-
데이터의 갯수가 적을 경우 과적합이 발생하기 쉽다.
-
적은 데이터의 갯수에 대한 기준은 애매하지만 LightGBM의 공식 문서에서 10,000건 이하라고 기술하였다.
트리 기반 알고리즘 특징
-
기존의 대부분 트리 기반 알고리즘은 트리의 깊이를 효과적으로 줄이기 위한 균형 트리 분할(Level Wise) 방식을 사용한다.
-
최대한 균형 잡힌 트리를 유지하면서 분할하기 때문에 깊이가 최소화 되며 오버피팅에 보다 강한 구조를 가진다.
-
하지만 균형을 맞추기 위한 시간이 오래 걸리는 단점이 있다.
LightGBM 특징
-
LightGBM은 일반 GBM 계열의 트리 분할 방법과 다르게 리프 중심 트리 분할(Leaf Wise) 방식을 사용한다.
-
트리의 균형을 맞추지 않고 최대 손실 값(max delta loss)을 가지는 리프 노드를 지속적으로 분할하여 깊이가 증가하고 비대칭적인 트리를 생성한다.
-
이렇게 생성된 트리는 학습을 반복할수록 결국은 균형 트리 분할 방식보다 예측 오류 손실을 최소화 할 수 있다는 것이 LightGBM 구현사상이다.
1.1 LightGBM 하이퍼 파라미터
LightGBM도 파이썬 래퍼, 사이킷런 래퍼가 있지만 여기선 사이킷런 기준으로 정리하였다.
주요 파라미터
-
n_estimators [default: 100]: GBM과 XGB의 n_estimators와 같은 파라미터
-
learning_rate [defalut: 0.1]: GBM과 XGB의 학습률(learning_rate)과 같은 파라미터, 일반적으로 n_estimators를 높이고 learning_rate를 낮추면 예측 성능이 향상하지만 마찬가지로 과적합 이슈 및 소요 시간 증가의 문제가 있다.
-
max_depth [default: 1]: 트리 기반 알고리즘의 max_depth와 같다. 0보다 작은 값을 지정하면 깊이 제한이 없다. LightGBM은 Leaf Wise 방식이므로 깊이가 상대적으로 더 깊다.
-
min_child_samples [default: 20]: 결정 트리의 min_samples_leaf와 같은 파라미터로 리프 노드가 되기 위해 최소한으로 필요한 샘플 수
-
num_leaves [default: 31]: 하나의 트리가 가질 수 있는 최대 리프 개수
-
boosting [default: gbdt]: 부스팅의 트리를 생성하는 알고리즘을 지정하며 gbdt는 일반적인 그래디언트 부스팅 결정 트리이며 rf는 랜덤 포레스트이다.
-
subsample [default: 1]: GBM과 XGB의 subsample과 같은 파라미터
-
colsample_bytree [default: 1]: XGB의 colsample_bytree와 같은 파라미터로 개별 트리를 학습할 때마다 무작위로 선택하는 피처의 비율
-
reg_lambda [default: 0]: XGB의 reg_lambda와 같은 파라미터로 L2 regulation 제어를 위한 값이다. 피처 개수가 많을 경우 적용을 검토하며 값이 클수록 과적합 감소 효과가 있다.
-
reg_alpha [default: 0]: XGB의 reg_alpha와 같은 파라미터로 L1 regulation 제어를 위한 값이다. 피처 개수가 많을 경우 적용을 검토하며 값이 클수록 과적합 감소 효과가 있다.
학습 태스크 파라미터
- objective: 최솟값을 가져야할 손실함수를 정의한다. XGB의 objective 파라미터와 동일하다.
1.2 위스콘신 유방암 예측
LightGBM 학습/예측
from lightgbm import LGBMClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
dataset = load_breast_cancer()
X_features = dataset.data
y_label = dataset.target
X_train, X_test, y_train, y_test = train_test_split(X_features, y_label, test_size=0.2, random_state=156)
# eval_set
evals = [ (X_test, y_test) ]
# 학습 (조기 중단 지정)
lgbm_wrapper = LGBMClassifier(n_estimators=4000)
lgbm_wrapper.fit(X_train, y_train,
# 조기 중단 파라미터
early_stopping_rounds = 100, eval_metric = "logloss", eval_set = evals,
verbose=True)
[1] valid_0's binary_logloss: 0.565079
Training until validation scores don't improve for 100 rounds
[2] valid_0's binary_logloss: 0.507451
[3] valid_0's binary_logloss: 0.458489
[4] valid_0's binary_logloss: 0.417481
[5] valid_0's binary_logloss: 0.385507
...
[40] valid_0's binary_logloss: 0.123162
[41] valid_0's binary_logloss: 0.125592
[42] valid_0's binary_logloss: 0.128293
[43] valid_0's binary_logloss: 0.128123
[44] valid_0's binary_logloss: 0.12789
[45] valid_0's binary_logloss: 0.122818
...
[141] valid_0's binary_logloss: 0.196378
[142] valid_0's binary_logloss: 0.196367
[143] valid_0's binary_logloss: 0.19869
[144] valid_0's binary_logloss: 0.200352
[145] valid_0's binary_logloss: 0.19712
Early stopping, best iteration is:
[45] valid_0's binary_logloss: 0.122818
LGBMClassifier(n_estimators=4000)
-
조기 중단으로 145번 반복까지만 수행하고 학습을 종료하였다.
-
결과창이 너무 길어 직접 삭제해두었다.
-
XGBoost 포스팅과 마찬가지로 평가 수행 데이터로 test 데이터를 사용하였으며 학습시 test 데이터가 미리 참고 될 수 있으므로 주의하여야 한다.
LightGBM 예측/평가
# 3장에서 사용한 성능 평가 함수
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix
from sklearn.metrics import f1_score, roc_auc_score
def get_clf_eval(y_test, pred=None, pred_proba_po=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)
auc = roc_auc_score(y_test, pred_proba_po)
print("오차 행렬")
print(confusion)
print(f"정확도: {accuracy:.4f}, 정밀도: {precision:.4f}, 재현율: {recall:.4f}, F1: {f1:.4f}, AUC: {auc:.4f}")
# 예측
preds = lgbm_wrapper.predict(X_test)
pred_proba = lgbm_wrapper.predict_proba(X_test)[:,1]
# 평가
get_clf_eval(y_test, preds, pred_proba)
오차 행렬
[[33 4]
[ 1 76]]
정확도: 0.9561, 정밀도: 0.9500, 재현율: 0.9870, F1: 0.9682, AUC: 0.9905
- 앞서 XGBoost 포스팅과 비교하면 전체적인 성능은 낮게 나오지만 train과 test 데이터 크기가 작아서 알고리즘 간 성능 비교는 큰 의미가 없다.
LightGBM 피처별 중요도
from lightgbm import plot_importance
plot_importance(lgbm_wrapper)
plt.show()
- LightGBM 역시 XGB와 마찬가지로 피처별 중요도 시각화 함수가 내장되어 있으며 명령어 역시 동일하다.
Leave a comment