위키북스의 파이썬 머신러닝 완벽 가이드 책을 토대로 공부한 내용입니다.
LightGBM은 XGBoost와 함께 부스팅 계열 알고리즘에서 가장 각광받고 있다. XGBoost는 뛰어난 부스팅 알고리즘이지만, GridSearchCV로 하이퍼 파라미터 튜닝을 하다보면 시간이 너무 오래 걸려서 많은 파라미터를 튜닝하기에 어려움이 있다. LightGBM의 가장 큰 장점은 XGBoost보다 학습에 걸리는 시간이 훨씬 적고 메모리 사용량도 상대적으로 적다는 점이다. LightGBM의 'Light'는 바로 이러한 장점 때문에 붙여진 이름이다. 그리고 XGBoost의 예측 성능과 별다른 차이가 없고, 기능상의 다양성은 약간 더 많다. LightGBM의 한 가지 단점으로는 적은 dataset에 적용할 경우 과적합이 발생하기 쉽다는 것이다. 적은 dataset이란 일반적으로 10,000건 이하의 dataset 정도라고 LightGBM 공식 문서에서 기술하고 있다.
LightGBM은 일반 GBM 계열의 트리 분할 방법과 다르게 리프 중심 분할(Leaf Wise) 방식을 사용한다. 기존의 대부분 트리 기반 알고리즘은 트리의 깊이를 효과적으로 줄이기 위한 균형 트리 분할(Level Wise) 방식을 사용한다. 즉, 최대한 균형 잡힌 트리를 유지하면서 분할하기 때문에 트리의 깊이가 최소화할 수 있고, 이렇게 균형 잡힌 트리는 오버피팅에 보다 더 강한 구조를 가질 수 있다고 알려져있다. 하지만 균형을 맞추기 위해 시간이 오래 걸린다는 단점이 있다. LightGBM의 리프 중심 분할 방식은 트리의 균형을 맞추지 않고, 최대 손실 값(max delta loss)을 가지는 리프 노드를 지속적으로 분할하면서 트리의 깊이가 깊어지고 비대칭적인 규칙 트리가 생성된다. 하지만 이렇게 최대 손실값을 가지는 리프 노드를 지속적으로 분할해 생성된 규칙 트리는 학습을 반복할수록 결국은 균형 트리 분할 방식보다 예측 오류 손실을 최소화 할 수 있다는 것이 LightGBM의 구현 사상이다.
또한 XGBoost와 마찬가지로 대용량 데이터에 대한 뛰어난 예측 성능과 병렬 컴퓨팅 기능을 제공하며 최근에는 GPU까지 지원하고 있다. LightGBM의 파이썬 개체명은 lightgbm이다. XGBoost와 마찬가지로 초기에는 파이썬 래퍼용만 개발됬으나 이 후에 사이킷런 래펴용도 추가로 개발되었고 lightgbm 패키지 내에 두개의 래퍼 모듈을 모두 가지고 있다. 사이킷런 래퍼 LightGBM 클래스는 분류를 위한 LGBMClassifier 클래스와 회귀를 위한 LGBMRegressor 클래스이다.
LightGBM 하이퍼 파라미터는 XGBoost와 많은 부분이 유사하다. 주의할 점은 리프 중심 트리 분할 방식으로 트리가 깊어지므로 트리 특성에 맞는 하이퍼 파라미터 설정이 필요하다.
주요파라미터
- num_iterations [default=100]: 반복 수행하려는 트리의 개수를 지정한다. 크게 지정할수록 예측 성능이 높아질 수 있으나, 너무 크게 지정하면 오히려 과적합으로 성능이 저하될 수 있다. 사이킷런 GBM과 XGBoost의 사이킷런 호환 클래스의 n_estimators와 같은 파라미터이므로 LightGBM의 사이킷런 호환 클래스에서는 num_iterations로 이름이 변경되었다.
- learning_rate [default=0.1]: 0에서 1사이의 값을 지정하며 부스팅 스텝을 반복적으로 수행할 때 업데이트되는 학습률 값이다. 일반적으로 n_estimators를 크게 하고 learning_rate를 작게 해서 예측 성능을 향상시킬 수 있으나, 마찬가지로 과적합 이슈와 학습 시간이 길어지는 부정적인 영향도 고려해야 한다. GBM, XGBoost의 learning_rate와 같은 파라미터이다.
- max_depth [default=-1]: 트리 기반 알고리즘의 max_depth와 같다. 0보다 작은 값을 지정하면 깊이에 제한이 없다. 지금까지 소개한 Depth wise 방식의 트리와 다르게 LightGBM은 Leaf wise 기반이므로 깊이가 상대적으로 더 깊다.
- min_data_in_leaf [default=20]: 결정 트리의 min_samples_leaf와 같은 파라미터이다. 하지만 사이킷런 래퍼 LightGBM 클래스인 LightGBMClassifier에서는 min_child_samples 파라미터로 이름이 변경된다. 최종 결정 클래스인 리프 노드가 되기 위해서 최소한으로 필요한 레코드 수이며, 과적합을 제어하기 위한 파라미터이다.
- num_leaves [default=31]: 하나의 트리가 가질 수 있는 최대 리프 개수이다.
- boosting [default=gbdt]: 부스팅의 트리를 생성하는 알고리즘을 기술한다.
- gbdt : 일반적인 그래디언트 부스팅 결정 트리
- rf : 랜덤 포레스트
- bagging_fraction [default=1.0]: 트리가 커져서 과적합되는 것을 제어하기 위해서 데이터를 샘플링하는 비율을 지정한다. 사이킷런의 GBM과 XGBClassifier의 subsample 파라미터와 동일하기에 사이킷런 래퍼 LightGBM인 LightGBMClassifier에서는 subsample로 동일하게 파라미터 이름이 변경된다.
- feature_fraction [default=1.0]: 개별 트리를 학습할 때마다 무작위로 선택하는 feature의 비율이다. 과적합을 막기 위해 사용된다. GBM의 max_features와 유사하며, XGBClassifier의 colsample_bytree와 똑같으므로 LightGBM Classifier에서는 동일하게 colsample_bytree로 변경된다.
- lambda_l2 [default=0.0]: L2 regulation 제어를 위한 값이다. feature 개수가 많을 경우 적용을 검토하며 값이 클수록 과적합 감소 효과가 있다. XGBClassifier의 reg_lambda와 동일하므로 LightGBMClassifier에서는 reg_lambda로 변경된다.
- lambda l1 [default=0.0]: L1 regulation 제어를 위한 값이다. L2와 마찬가지로 과적합 제어를 위한 것이며, XGBClassifier의 reg_alpha와 동일하므로 LightGBMClassifier에서는 reg_alpha로 변경된다.
Learning Task 파라미터
- objective: 최솟값을 가져야 할 손실함수를 정의한다. Xgboost의 objective 파라미터와 동일하다. 애플리케이션 유형, 즉 회귀, 다중 클래스 분류, 이진 분류인지에 따라서 objective인 손실 함수가 지정된다.
num_leaves의 개수를 중심으로 min_child_samples(min_data_in_leaf), max_depth를 함께 조정하면서 모델의 복잡도를 줄이는 것이 기본 튜닝 방안이다.
- num_leaves는 개별 트리가 가질 수 있는 최대 리프의 개수이고 LightGBM 모델의 복잡도를 제어하는 주요 파라미커이다. 일반적으로 num_leaves의 개수를 높이면 정확도가 높아지지만, 반대로 트리의 깊이가 깊어지고 모델이 복잡도가 커져 과적합 영향도가 커진다.
- min_data_in_leaf는 사이킷런 래퍼 클래스에서는 min_child_samples로 이름이 바뀐다. 과적합을 개선하기 위한 중요한 파라미터이다. num_leaves와 학습 데이터의 크기에 따라 달라지지만, 보통 큰 값으로 설정하면 트리가 깊어지는 것을 방지한다.
- max_depth는 명시적으로 깊이의 크기를 제한한다. num_leaves, min_data_in_leaf와 결합해 과적합을 개선하는 데 사용한다.
learning_rate를 작게 하면서 n_estimators를 크게 하는 것은 부스팅 계열 튜닝에서 가장 기본적인 튜닝 방안이므로 이를 적용하는 것도 좋지만 n_estimators를 너무 크게 하는 것은 과적합으로 오히려 성능이 저하될 수 있다. 이외에도 과적합을 제어하기 위해 reg_lambda, reg_alpha와 같은 regularization을 적용하거나 학습 데이터를 사용할 feature 개수나 데이터 샘플링 레코드 개수를 줄이기 위해 colsample_bytree, subsample 파라미터를 적용할 수 있다.
사아킷런 래퍼 LightGBM의 하이퍼 파라미터는 사이킷런 XGBoost에 맞춰서 변경하여 많은 하이퍼 파라미터가 똑같다.
파이썬 래퍼 LightGBM 사이킷런 래퍼 LightGBM 사이킷런 래퍼 XGBoost num_iterations n_estimators n_estimators learning_rate learning_rate learning_rate max_depth max_depth max_depth min_data_in_leaf min_child_samples N/A bagging_fraction subsample subsample feature_fraction colsample_bytree colsample_bytree lambda_l2 reg_lambda reg_lambda lambda_l1 reg_alpha reg_alpha early_stopping_round early_stopping_rounds early_stopping_rounds num_leaves num_leaves N/A min_sum_hessian_in_leaf min_child_weight min_child_weight
위스콘신 유방암 dataset을 이용해 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() ftr = dataset.data target = dataset.target # 전체 데이터 중 80%는 학습용 데이터, 20%는 테스트용 데이터 추출 X_train, X_test, y_train, y_test=train_test_split(ftr, target, test_size=0.2, random_state=156 ) # 앞서 XGBoost와 동일하게 n_estimators는 400 설정. lgbm_wrapper = LGBMClassifier(n_estimators=400) # LightGBM도 XGBoost와 동일하게 조기 중단 수행 가능. evals = [(X_test, y_test)] lgbm_wrapper.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="logloss", eval_set=evals, verbose=True) preds = lgbm_wrapper.predict(X_test) pred_proba = lgbm_wrapper.predict_proba(X_test)[:, 1]
[output] 조기 중단으로 147번 반복까지만 수행하고 학습이 종료되었다.
get_clf_eval(y_test, preds, pred_proba)
[output] 정확도가 약 94.74%로 XGBoost의 경우보다 작지만 학습 dataset과 테스트 dataset의 크기가 작아 알고리즘 간의 성능 차이 비교는 큰 의미가 없다.
# 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)
[output] lightGBM에 내장된 plotimportance()도 넘파이 feature 데이터로 학습할 경우 feature 명을 알 수 없기에 Column 뒤에 feature 순서대로 숫자를 붙여서 X축에 나열한다.