Post

[Python] ML-LightGBM

[Python] ML-LightGBM

LightGBM 개념

LightGBM은 Microsoft에서 개발한 빠르고 효율적인 Gradient Boosting 프레임워크. 기존 Gradient Boost의 느린 속도 문제를 두 가지 핵심 기술로 해결

1
2
3
4
5
6
기존 Gradient Boost의 문제:
→ 모든 샘플과 모든 변수를 탐색 → 느림

LightGBM의 해결책:
→ GOSS로 중요 샘플만 선택
→ EFB로 희소 변수를 묶어 변수 수 축소

LightGBM_Framework

두 가지 핵심 기술

1. GOSS (Gradient-based One-Side Sampling)

1
2
3
4
5
기울기(잔차)가 큰 샘플 → 전부 사용 (학습에 중요)
기울기가 작은 샘플 → 일부만 랜덤 선택

→ 정보 손실 최소화하면서 샘플 수를 줄임
→ 학습 속도 향상

2. EFB (Exclusive Feature Bundling)

1
2
3
4
5
6
7
동시에 0이 아닌 값을 가지지 않는 희소 변수들을 하나로 묶음
즉, 서로 동시에 나타나지 않는 변수들을 하나로 합쳐서, 모델이 공부해야 할 과목 수를 줄여주는 기술
-> 굳이 고려하지 않아도 되는 경우의 수를 제외하는 방법.

예: 원-핫 인코딩된 변수들은 동시에 1이 되지 않음
→ 여러 변수를 하나로 묶어 변수 수를 효과적으로 줄임
→ 메모리 및 계산 효율 향상

Leaf-wise vs Level-wise 트리 성장

1
2
3
4
5
6
7
8
9
Level-wise (일반적인 방식):
같은 깊이의 모든 노드를 분할
→ 균형 잡힌 트리, 과적합 위험 낮음

Leaf-wise (LightGBM):
손실 감소가 가장 큰 Leaf 하나만 분할
→ 불균형하지만 정확한 트리
→ 빠른 수렴, 소규모 데이터에서 과적합 주의
→ num_leaves로 복잡도 제어

언제 사용하는가

사용해야 할 때

상황이유
대용량 데이터 (수십만 건 이상)GOSS + EFB로 XGBoost보다 훨씬 빠른 학습
학습 속도가 중요한 실무 환경동일 성능 기준 가장 빠른 Boosting 계열
범주형 변수가 많을 때One-Hot Encoding 없이 category 타입으로 직접 처리
메모리가 제한적인 환경EFB로 변수 수를 효과적으로 압축
빠른 실험이 필요할 때빠른 반복 학습으로 하이퍼파라미터 탐색 용이

사용하지 말아야 할 때

상황이유
소규모 데이터 (수천 건 이하)Leaf-wise 성장으로 과적합 위험 높아짐
모델 해석이 핵심인 경우블랙박스 모델로 개별 예측 설명 어려움
이미지, 텍스트, 시계열딥러닝 계열이 더 적합

실무 활용 사례

1
2
3
4
금융    : 대규모 신용카드 사기 탐지 (실시간성 + 대용량)
커머스  : 수백만 고객의 구매 예측 및 추천
광고    : 수억 건 로그 기반 CTR(클릭률) 예측
에너지  : 대규모 센서 데이터 기반 설비 이상 탐지

Parameters

Parameter설명Default
n_estimators트리 수100
learning_rate학습률0.1
num_leaves트리당 최대 리프 수 (핵심)31
max_depth최대 깊이 (-1: 제한 없음)-1
min_child_samplesLeaf 노드의 최소 샘플 수20
subsample행 샘플링 비율1.0
colsample_bytree변수 샘플링 비율1.0
  • num_leaves : 트리당 최대 Leaf 수 — LightGBM의 핵심 파라미터
    • 값 변화별 효과
      • 클수록 → 복잡한 모델, 과적합 ↑, 학습 시간 증가
      • 작을수록 → 단순한 모델, 과적합 ↓
    • 2^max_depth보다 작게 설정 권장
    • 소규모 데이터: 31 이하, 대규모 데이터: 64~128 시도
  • learning_rate : 각 트리의 기여도 축소 계수
    • 값 변화별 효과
      • 클수록 → 빠른 수렴, 과적합 위험 ↑
      • 작을수록 → 안정적인 수렴, n_estimators 더 필요
    • 실무 권장: 0.05~0.1 + Early Stopping 조합
  • min_child_samples : Leaf 노드에 필요한 최소 샘플 수
    • 값 변화별 효과
      • 클수록 → 분할 제한 → 과적합 ↓
      • 작을수록 → 잦은 분할 → 과적합 ↑
    • 소규모 데이터에서 과적합 방지 시 20~50으로 증가
  • subsample / colsample_bytree : 행/열 샘플링 비율
    • 값 변화별 효과
      • 1.0보다 작으면 → 무작위성 추가 → 과적합 ↓, 학습 빠름
      • 실무 권장: 0.7~0.9

실습 — Titanic 생존자 예측

I. Library & Data Load

1
2
3
4
5
6
7
8
9
10
11
12
import warnings
warnings.filterwarnings(action = 'ignore')  # 경고 메시지 숨김

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from lightgbm import LGBMClassifier
import lightgbm as lgb
from sklearn.metrics import accuracy_score, confusion_matrix

import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'AppleGothic'
1
titanic = pd.read_csv('./Data/Titanic.csv')  # 데이터 로드

II. Preprocessing

II-I. Feature Engineering

1
2
3
4
5
6
7
8
9
10
titanic['FamSize'] = titanic['SibSp'] + titanic['Parch']  # 가족 수 파생변수 생성

use_cols = ['Survived', 'Pclass', 'Sex', 'Age', 'FamSize', 'Fare', 'Embarked']
titanic = titanic[use_cols].dropna(subset = ['Age'])  # 결측값 제거

titanic[['Survived', 'Pclass', 'Sex', 'Embarked']] = \
    titanic[['Survived', 'Pclass', 'Sex', 'Embarked']].astype('category')  # 범주형으로 변환
titanic['Age'] = titanic['Age'].astype('int')  # 정수형으로 변환

titanic = pd.get_dummies(titanic, columns = ['Pclass', 'Sex', 'Embarked'], drop_first = True)  # 원-핫 인코딩

II-II. Train & Test Split

1
2
3
y = titanic['Survived']
X = titanic.drop(['Survived'], axis = 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)  # 훈련/테스트 분할 (75:25)

III. Model Train

1
2
3
4
5
6
7
8
9
10
LGB = LGBMClassifier(
    n_estimators = 200,
    learning_rate = 0.05,
    num_leaves = 31,
    min_child_samples = 20,
    random_state = 0,
    verbose = -1
)

LGB.fit(X_train, y_train)  # 모델 학습

IV. Early Stopping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
X_tr, X_val, y_tr, y_val = train_test_split(X_train, y_train, test_size = 0.2, random_state = 0)

LGB_ES = LGBMClassifier(
    n_estimators = 1000,
    learning_rate = 0.05,
    num_leaves = 31,
    random_state = 0,
    verbose = -1
)

LGB_ES.fit(
    X_tr, y_tr,
    eval_set = [(X_val, y_val)],
    callbacks = [lgb.early_stopping(stopping_rounds = 50, verbose = False)]
)

print(f"최적 트리 수: {LGB_ES.best_iteration_}")  # 최적 트리 수 (조기 종료 시점)

V. 범주형 변수 직접 처리

LightGBM의 강점 — One-Hot Encoding 없이 범주형 변수를 그대로 사용 가능

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
titanic_cat = pd.read_csv('./Data/Titanic.csv')  # 데이터 로드
titanic_cat['FamSize'] = titanic_cat['SibSp'] + titanic_cat['Parch']  # 가족 수 파생변수 생성

use_cols = ['Survived', 'Pclass', 'Sex', 'Age', 'FamSize', 'Fare', 'Embarked']
titanic_cat = titanic_cat[use_cols].dropna(subset = ['Age'])  # 결측값 제거
titanic_cat['Age'] = titanic_cat['Age'].astype('int')  # 정수형으로 변환

cat_features = ['Pclass', 'Sex', 'Embarked']
for col in cat_features:
    titanic_cat[col] = titanic_cat[col].astype('category')  # 범주형으로 변환

y_cat = titanic_cat['Survived']
X_cat = titanic_cat.drop('Survived', axis = 1)
X_tr_cat, X_te_cat, y_tr_cat, y_te_cat = train_test_split(X_cat, y_cat, test_size = 0.25, random_state = 0)

LGB_cat = LGBMClassifier(n_estimators = 200, random_state = 0, verbose = -1)
LGB_cat.fit(X_tr_cat, y_tr_cat, categorical_feature = cat_features)  # 범주형 변수 직접 지정 (One-Hot 불필요)

print(f"정확도 : {LGB_cat.score(X_te_cat, y_te_cat) * 100:.2f}%")

VI. Evaluation Score

1
2
3
4
5
6
7
8
9
pred = LGB.predict(X_test)  # 클래스 예측
cfx = confusion_matrix(y_test, pred)  # 혼동 행렬 계산
# [0,0]=TN, [0,1]=FP, [1,0]=FN, [1,1]=TP
sensitivity = cfx[1, 1] / (cfx[1, 0] + cfx[1, 1])  # 민감도: TP / (TP + FN)
specificity = cfx[0, 0] / (cfx[0, 0] + cfx[0, 1])  # 특이도: TN / (TN + FP)

print(f"정확도 : {accuracy_score(y_test, pred) * 100:.2f}%")  # 정확도 계산
print(f"민감도 : {sensitivity * 100:.2f}%")
print(f"특이도 : {specificity * 100:.2f}%")
1
2
3
정확도 : 83.80%
민감도 : 75.00%
특이도 : 89.32%

장단점

장점

  • XGBoost보다 빠른 학습 속도
  • 메모리 효율이 높음
  • 범주형 변수 자동 처리 지원
  • 대용량 데이터에 최적

단점

  • 소규모 데이터에서 Leaf-wise 성장으로 과적합 위험
  • num_leaves 등 LightGBM 고유 파라미터 이해 필요
  • XGBoost보다 직관적 이해가 어려움
This post is licensed under CC BY 4.0 by the author.