정형 데이터 분석을 하다 보면 모델 선택지가 생각보다 빠르게 좁혀집니다. 전처리 끝내고 베이스라인 돌려보고 나면 결국 XGBoost나 LightGBM 중 하나로 수렴하는 경우가 많거든요. 그런데 막상 "왜 XGBoost 쓰셨어요?"라는 질문을 받으면 "성능이 좋아서요"로 끝나는 경우가 꽤 있습니다. 🌿
랜덤 포레스트가 트리들을 독립적으로 병렬 학습하는 방식이었다면, 부스팅은 정반대입니다. 이전 트리가 틀린 부분을 다음 트리가 이어받아 순차적으로 고쳐나가는 구조인데, 이 차이가 어디서 오는지 이해하면 두 모델을 고르는 기준도 달라집니다.
오늘은 Gradient Boosting의 핵심 원리부터 XGBoost가 기존 GBM보다 나아진 이유, LightGBM이 빠른 구조적 이유까지 순서대로 정리해보겠습니다.
1. 배깅과 부스팅: 무엇이 다른가

랜덤 포레스트는 트리들이 서로 독립적으로 학습됩니다. 각 트리가 서로의 결과를 모르는 채로 예측을 내놓고, 마지막에 다수결로 합산합니다. 목표는 분산(Variance) 감소입니다.
부스팅은 반대입니다. 트리들이 순서대로 학습되고, 각 트리는 이전 트리가 틀린 부분에 집중합니다. 목표는 편향(Bias) 감소입니다.
배깅: 독립적인 트리들의 평균 → 분산 감소
부스팅: 이전 트리의 오차를 다음 트리가 학습 → 편향 감소
| 항목 | 배깅 | 부스팅 |
|---|---|---|
| 학습 방식 | 병렬 (독립적) | 순차적 (의존적) |
| 목표 | 분산 감소 | 편향 감소 |
| 오답 처리 | 각 트리가 독립 예측 | 이전 오차를 다음 트리가 집중 학습 |
| 대표 알고리즘 | Random Forest | GBM, XGBoost, LightGBM |
2. Gradient Boosting의 핵심 아이디어
부스팅의 기본 아이디어는 약한 모델(Weak Learner)을 순차적으로 이어붙여 강한 모델을 만드는 것입니다. Gradient Boosting은 여기서 한 발 더 나아갑니다. 이전 모델의 잔차(Residual)를 다음 모델이 직접 학습합니다.
잔차 = 실제값 − 예측값
1번 트리 예측 후 남은 잔차 → 2번 트리가 학습
2번 트리 예측 후 남은 잔차 → 3번 트리가 학습
반복할수록 전체 예측이 실제값에 가까워집니다
2.1 왜 이름에 Gradient가 붙는가
정확히는 잔차를 줄이는 게 아니라, 손실함수의 그래디언트(기울기) 방향으로 예측을 개선하는 것입니다.
손실함수가 MSE라면 그래디언트가 잔차 자체와 일치합니다. 하지만 로그 손실이나 Huber 손실 같은 다른 함수를 쓰면 그래디언트는 단순 잔차와 달라집니다. 이 유연성 덕분에 회귀, 분류, 랭킹 문제 모두에 Gradient Boosting을 적용할 수 있습니다.
경사하강법 글에서 다뤘던 것처럼 파라미터 공간에서 그래디언트 반대 방향으로 이동하면 손실이 줄어듭니다. Gradient Boosting은 그 원리를 파라미터가 아니라 함수 공간에서 적용한 것입니다. 방향은 같습니다.
3. XGBoost: 기존 GBM보다 강해진 이유
XGBoost(eXtreme Gradient Boosting)는 2016년 Tianqi Chen이 발표했습니다. Gradient Boosting의 아이디어는 그대로 가져가면서, 실제 사용 환경에서 문제가 됐던 부분을 세 가지 방식으로 개선했습니다.
3.1 정규화 항 내장
기존 GBM의 손실함수에는 모델 복잡도에 대한 패널티가 없었습니다. 트리가 원하는 만큼 복잡해질 수 있어서 과적합에 취약했습니다.
XGBoost는 목적함수 자체에 정규화 항을 추가했습니다.
목적함수 = 손실함수 + Ω(트리 복잡도)
Ω는 트리의 리프 수와 리프 가중치 크기에 대한 패널티입니다. 하이퍼파라미터 gamma(최소 손실 감소량)와 lambda(L2 정규화 계수)가 이 항을 조절합니다. 트리가 지나치게 복잡해지는 걸 학습 과정에서 자동으로 억제합니다.
3.2 2차 도함수(헤시안) 활용
기존 GBM은 손실함수의 1차 도함수(그래디언트)만 사용해 최적 분기점을 찾았습니다. XGBoost는 2차 도함수(헤시안, Hessian)까지 사용합니다.
1차 도함수만 사용 → 기울기를 보고 방향만 결정
2차 도함수까지 사용 → 기울기 변화율까지 보고 방향과 보폭을 함께 결정
2차 근사가 더 정확하기 때문에 같은 반복 횟수에서 더 좋은 분기점을 찾습니다
면접에서 "XGBoost가 왜 좋은가요?"라는 질문에 단순히 성능 때문이라고 답하는 것과, 이 부분까지 설명하는 건 받아들이는 쪽에서 느낌이 다릅니다.
3.3 결측값 자동 처리
기존 GBM은 결측값을 사전에 처리해야 했습니다. XGBoost는 결측값이 있는 샘플을 분기할 때 왼쪽과 오른쪽 중 어느 방향이 손실을 더 줄이는지 학습 과정에서 자동으로 결정합니다.
실무에서 raw 데이터를 그대로 넣어도 어느 정도 돌아가는 게 이 기능 덕분입니다. 전처리가 완벽하지 않은 환경에서도 빠르게 실험할 수 있다는 게 실질적인 장점입니다.
4. LightGBM: XGBoost보다 빠른 이유

Microsoft가 2017년 발표한 LightGBM은 알고리즘 자체는 XGBoost와 거의 같습니다. 차이는 트리를 성장시키는 방식에 있고, 이게 속도와 메모리 효율에서 큰 차이를 만듭니다.
4.1 Level-wise vs Leaf-wise
XGBoost는 Level-wise 방식으로 트리를 성장시킵니다. 같은 깊이의 노드를 전부 분기한 뒤 다음 레벨로 넘어갑니다. 트리가 균형 있게 성장하지만 불필요한 분기도 함께 포함됩니다.
LightGBM은 Leaf-wise 방식을 씁니다. 전체 리프 중에서 손실 감소가 가장 큰 리프 하나만 골라 분기합니다. 같은 횟수의 분기에서 더 많은 손실을 줄입니다. 트리가 비대칭으로 깊어지는 게 특징입니다.
| 항목 | XGBoost (Level-wise) | LightGBM (Leaf-wise) |
|---|---|---|
| 트리 형태 | 균형 잡힌 트리 | 비대칭으로 깊어지는 트리 |
| 속도 | 상대적으로 느림 | 빠름 |
| 과적합 위험 | 낮음 | 데이터 적을 때 주의 — num_leaves 조절 필요 |
4.2 GOSS와 EFB
LightGBM이 빠른 이유가 하나 더 있습니다. 학습 데이터와 피처 수를 효율적으로 줄이는 두 가지 기법을 내장하고 있습니다.
- GOSS (Gradient-based One-Side Sampling): 그래디언트가 큰 샘플(아직 잘 학습 안 된 것)은 전부 유지하고, 그래디언트가 작은 샘플은 일부만 랜덤 샘플링합니다. 중요한 데이터는 놓치지 않으면서 학습 데이터 양을 줄입니다.
- EFB (Exclusive Feature Bundling): 동시에 0이 아닌 값을 갖지 않는 피처들을 하나로 묶습니다. 원-핫 인코딩처럼 희소한 피처가 많을 때 효과적입니다. 피처 수를 줄여 메모리와 속도를 동시에 개선합니다.
5. 주요 하이퍼파라미터
| 파라미터 | 의미 | 실무 팁 |
|---|---|---|
| n_estimators | 부스팅 반복 횟수 (트리 수) | 크게 잡고 early_stopping_rounds로 자동 조절 |
| learning_rate | 각 트리의 기여 축소 계수 | 0.01~0.1 사이, 작을수록 n_estimators를 크게 |
| max_depth | 트리 최대 깊이 | 3~6이 일반적, 깊을수록 과적합 위험 |
| subsample | 트리마다 사용할 데이터 비율 | 0.7~0.9, 과적합 방지 + 속도 향상 효과 |
| num_leaves (LGB) | 최대 리프 수 (LightGBM 전용) | 2^max_depth보다 작게 설정, 기본값 31 |
6. 코드로 확인하기
import xgboost as xgb
import lightgbm as lgb
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import time
data = load_breast_cancer()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# XGBoost
xgb_model = xgb.XGBClassifier(
n_estimators=300,
learning_rate=0.05,
max_depth=4,
subsample=0.8,
eval_metric='logloss',
random_state=42,
verbosity=0
)
start = time.time()
xgb_model.fit(X_train, y_train)
xgb_time = time.time() - start
xgb_acc = accuracy_score(y_test, xgb_model.predict(X_test))
# LightGBM
lgb_model = lgb.LGBMClassifier(
n_estimators=300,
learning_rate=0.05,
max_depth=4,
num_leaves=15,
subsample=0.8,
random_state=42,
verbosity=-1
)
start = time.time()
lgb_model.fit(X_train, y_train)
lgb_time = time.time() - start
lgb_acc = accuracy_score(y_test, lgb_model.predict(X_test))
print(f"XGBoost — 정확도: {xgb_acc:.4f} | 학습 시간: {xgb_time:.3f}초")
print(f"LightGBM — 정확도: {lgb_acc:.4f} | 학습 시간: {lgb_time:.3f}초")
XGBoost — 정확도: 0.9737 | 학습 시간: 0.312초
LightGBM — 정확도: 0.9737 | 학습 시간: 0.089초
정확도는 같지만 학습 시간은 약 3.5배 차이입니다. 이 차이는 데이터 규모가 커질수록 훨씬 벌어집니다. 수백만 건 이상의 데이터를 반복 실험하는 환경에서 LightGBM이 사실상 표준으로 쓰이는 이유입니다.
7. 실무에서 선택 기준
| 상황 | 추천 | 이유 |
|---|---|---|
| 대용량 데이터, 반복 실험 많은 환경 | LightGBM | 속도와 메모리 효율 모두 유리 |
| 데이터 적고 안정적인 결과 필요 | XGBoost | Level-wise 성장으로 과적합 위험 낮음 |
| 범주형 변수 많음 | LightGBM 또는 CatBoost | 인코딩 없이 범주형 직접 처리 가능 |
| 빠른 프로토타이핑 | LightGBM | 기본값 성능 높고 학습 빠름 |
정리
부스팅 계열은 정형 데이터에서 거의 항상 좋은 베이스라인을 보여줍니다. 그래서 별 고민 없이 쓰게 되는 경우가 많은데, 내부 동작을 이해하고 쓰는 것과 모르고 쓰는 건 하이퍼파라미터 튜닝이나 성능이 기대만큼 안 나올 때 차이가 납니다.
특히 learning_rate와 n_estimators의 관계, num_leaves로 인한 과적합 제어는 직접 한 번씩 바꿔보면서 감을 잡는 게 가장 빠릅니다. 코드 돌려보면서 파라미터 하나씩 건드려보는 걸 권장합니다. 🙂
'AI & ML > ML' 카테고리의 다른 글
| [머신러닝] 랜덤 포레스트: 나무가 많아지면 왜 더 강해지는가 (0) | 2026.05.24 |
|---|---|
| [머신러닝] 결정 트리: 모델이 스스로 질문을 만드는 방법 (0) | 2026.05.06 |
| [머신러닝] 로지스틱 회귀: 분류 문제를 확률로 푸는 방법 (0) | 2026.04.26 |
| [머신러닝] 선형 회귀: 가장 단순한 모델의 작동 원리 (0) | 2026.04.26 |
| [머신러닝] 지도학습(회귀모델 vs 분류모델) (3) | 2026.02.17 |
HELLO WORLD
안녕하세요. 데이터로 말하는 분석가 모모입니다.
데이터를 구조화하고 분석하는 과정과 실무에 활용되는 도구 중심의 내용을 기록합니다.