본문 바로가기

Machine Learning

Chapter5 : Machine Learning - Cross Validation, Ensemble Learning (XGBoosting, LightGBM, Random Forest)

 

 

머신러닝에서 “좋은 모델”은 당연하게도 학습 데이터에 잘 맞는 모델이 아니라, 

처음 보는 데이터에도 안정적으로 작동하는 모델입니다. 

그래서 모델을 이야기하기 전에 먼저 봐야 하는 것이 검증이며, 

여기서 가장 중요한 개념이 편향-분산 Trade-off입니다.

출처: Metacode 강의자료


모델이 너무 단순하면 중요한 패턴을 놓쳐 편향이 커지고, 

반대로 너무 복잡하면 노이즈까지 학습해 분산이 커집니다. 

결국 목표는 편향과 분산 사이의 균형점을 찾아 전체 예측 오차를 최소화하는 것입니다.

출처: Metacode 강의자료


편향-분산 분해의 핵심 수식은 아래처럼 정리할 수 있습니다.


$y = f^*(x) + \epsilon, \quad \epsilon \sim N(0,\sigma^2)$


$\mathrm{MSE} = \mathbb{E}\left[(y - \hat f(x))^2\right]$


$\mathrm{MSE} = \mathrm{Bias}^2(\hat f) + \mathrm{Var}(\hat f) + \sigma^2$

출처: Metacode 강의자료

 

이 문제를 제대로 다루기 위해 검증 데이터가 필요하며,

그 대표적인 방법이 K-fold cross validation입니다.

 

전체 데이터를 k개의 폴드로 나눈 뒤 한 폴드는 검증에 사용하고, 

나머지는 학습에 사용하는 과정을 반복해 평균 성능을 구하면

데이터 낭비를 줄이면서 일반화 성능을 더 신뢰성 있게 평가할 수 있습니다.

 

출처: Metacode 강의자료

 

K-fold cross validation의 핵심 형태는 아래처럼 쓸 수 있습니다.


$\mathrm{CV}_k = \frac{1}{k}\sum_{i=1}^{k} \mathrm{Measure}_i$

 

출처: Metacode 강의자료

 

하이퍼파라미터 튜닝과 최종 평가를 동시에 엄격하게 하고 싶다면 

nested K-fold cross validation이 필요합니다. 

이 방식은 바깥쪽 루프에서 평가를 하고 안쪽 루프에서 튜닝을 수행하기 때문에

튜닝 결과에 과도하게 낙관적인 평가가 붙는 문제를 줄여줍니다.

 

 

앙상블 학습이란?

 

출처: Metacode 강의자료


앙상블 학습은 여러 모델을 결합해 단일 모델보다 더 좋은 성능을 얻으려는 접근입니다. 

중요한 점은 “모델 수를 무작정 늘리는 것”이 아니라, 서로 다른 오류를 내는 모델들을 적절히 결합하는 것입니다.

 

앙상블 학습이 고평가받는 이유는 모든 데이터에서 항상 1등인 단일 알고리즘은 없기 때문입니다. 
실제로 앙상블은 상황에 따라 분산을 줄이거나, 편향을 줄이거나, 둘 다 줄이는 방향으로 설계될 수 있습니다.

 

앙상블의 대표 목표는 다음처럼 정리됩니다.

  • Bagging: 분산 감소
  • Boosting: 편향 감소
  • Stacking: 분산과 편향을 함께 줄이는 방향


앙상블 오차와 개별 모델 평균 오차의 관계를 설명하는 핵심 식도 중요합니다. 

개별 모델의 오차가 서로 독립적이고 평균이 0에 가깝다면

앙상블 오차는 개별 모델 평균 오차보다 훨씬 작아질 수 있습니다.

 

대표 수식은 아래처럼 정리할 수 있습니다.


$\mathrm{Error}_{avg} = \frac{1}{M}\sum_{i=1}^{M}\mathbb{E}[\epsilon_i^2]$


$\mathrm{Error}_{ens} = \mathbb{E}\left[\left(\frac{1}{M}\sum_{i=1}^{M} f_i - y\right)^2\right]$


$\frac{1}{M}\mathrm{Error}_{avg} \le \mathrm{Error}_{ens} \le \mathrm{Error}_{avg}$

 

여기서 핵심은 다양성(diversity) 입니다. 

개별 모델이 모두 비슷한 실수를 하면 앙상블 효과가 작고

서로 다른 관점에서 예측해 주어야 결합했을 때 성능이 좋아집니다.

출처: Metacode 강의자료


이 다양성을 수식으로 설명하는 것이 error-ambiguity decomposition입니다. 

앙상블 오차는 개별 모델 오차의 가중합에서 모델 간 다양성을 뺀 형태로 볼 수 있습니다.

$e_i = (f_i - d)^2$


$e_{ens} = (f_{ens} - d)^2$


$v_i = (f_i - f_{ens})^2$


$v_{ens} = \sum_i w_i (f_i - f_{ens})^2$


$e_{ens} = \sum_i w_i e_i - v_{ens}$

 

즉, 좋은 앙상블은 개별 모델의 성능도 좋아야 하고, 동시에 서로 충분히 달라야 합니다.

 

 

Bagging 계열: Bootstrap, Bagging, OOB, Random Forest

 


배깅은 같은 데이터를 여러 방식으로 다시 뽑아 여러 모델을 만들고

그 결과를 평균 또는 다수결로 결합하는 방식입니다.

여기서 핵심 재료가 바로 bootstrap이며

원본 데이터에서 복원추출로 새로운 학습 세트를 여러 개 만드는 과정입니다.

부트스트랩이 중요한 이유는 현실적으로 새로운 표본을 계속 얻기 어렵기 때문입니다.

이미 가진 데이터를 재구성해 여러 개의 약간씩 다른 학습 세트를 만들면

같은 알고리즘으로도 서로 다른 모델을 얻을 수 있습니다.

부트스트랩의 중요한 성질 하나는

표본 하나가 특정 bootstrap 샘플에 포함되지 않을 확률이 대략  $e^{-1}$ 이라는 점입니다.

그래서 한 번의 bootstrap 샘플에는 원본 데이터의 약 63.2% 정도가 포함되고 약 36.8%는 빠지게 됩니다.

$P(\text{sample } j \text{ is not selected in one draw}) = 1 - \frac{1}{n}$


$P(\text{sample } j \text{ is not selected in the whole bootstrap sample}) = \left(1 - \frac{1}{n}\right)^n$


$\lim_{n \to \infty}\left(1 - \frac{1}{n}\right)^n = \frac{1}{e}$

 

배깅 자체는 이 bootstrap 샘플들로 각각 모델을 학습시키고

최종 예측을 결합하는 방식입니다.

회귀에서는 평균을 쓰고 분류에서는 majority vote를 사용합니다.

배깅의 핵심 수식은 아래처럼 정리할 수 있습니다.

 

$\hat f_{bag}(x) = \frac{1}{B}\sum_{b=1}^{B} \hat f_b^*(x)$

 

$\hat f_{bag}(x) = \arg\max_c \sum_{b=1}^{B} I\left(\hat f_b^*(x)=c\right)$

 

배깅이 특히 트리 모델과 잘 맞는 이유는 결정트리가 원래 분산이 큰 모델이기 때문입니다.

여러 개의 트리를 평균내면 트리의 불안정성이 줄어들고 결과적으로 일반화 성능이 좋아집니다.


또 하나 중요한 개념이 OOB(out-of-bag) error입니다. 

각 트리는 bootstrap 샘플에 포함되지 않은 약 36.8%의 데이터를 자연스럽게 검증용 데이터처럼 갖게 되며

이를 이용해 별도의 검증 세트 없이도 성능을 추정할 수 있습니다.

OOB 예측은 특정 샘플을 학습에 사용하지 않은 트리들만 모아서 그 샘플을 예측한 결과입니다.

이런 OOB prediction을 모든 샘플에 대해 모으면 OOB error를 계산할 수 있고

이는 test error의 유효한 추정값으로 쓰일 수 있습니다.

Random Forest는 배깅에 랜덤한 변수 선택(random subspace) 을 추가한 알고리즘입니다. 

단순 배깅에서는 강력한 변수가 있으면 거의 모든 트리가 비슷한 상단 분할을 하게 되는데, 

랜덤 포레스트는 각 분할마다 일부 변수만 후보로 보게 하여 트리 간 상관을 줄입니다.


트리 간 상관이 줄면 앙상블의 분산 감소 효과가 더 커집니다.

분류 문제에서는 각 분할마다 보통 $sqrt{p}$ 개의 변수를 고려하는 설정이 자주 쓰이고

회귀 문제에서는 $p/3$ 수준의 선택이 많이 사용됩니다.

 

실무에서 자주 보는 랜덤 포레스트 하이퍼파라미터는 다음과 같습니다.

  • n_estimators: 트리 개수
  • max_features: 각 분할에서 고려할 변수 수
  • max_depth: 개별 트리의 최대 깊이


배깅과 랜덤 포레스트의 차이를 한 줄로 정리하면

배깅은 샘플을 랜덤하게 바꾸고, 랜덤 포레스트는 샘플과 변수 모두를 랜덤하게 바꿉니다.

 


부스팅 계열: AdaBoost, GBM, XGBoost, LightGBM

 


부스팅은 배깅과 달리 모델을 병렬로 만들지 않고 순차적으로 만듭니다. 

즉, 이전 단계 모델이 어디에서 틀렸는지를 다음 단계 모델이 보완하도록 연결해 가면서 

점점 강한 예측기를 만드는 방식입니다.

부스팅의 기본 철학은 약한 학습기(weak learner)를 여러 단계 이어 붙여 

강한 학습기(strong learner)를 만드는 것입니다. 

이 과정에서 중요한 하이퍼파라미터는 트리의 개수, 

각 트리의 깊이 또는 split 수, 학습률(learning rate)입니다.

 


AdaBoost

 


AdaBoost는 잘못 예측된 샘플에 더 큰 가중치를 부여해

다음 stump가 그 샘플에 더 집중하게 만드는 방식입니다.

보통 base learner로는 깊이가 1인 decision stump를 사용합니다.

AdaBoost의 핵심 수식은 아래처럼 정리할 수 있습니다.

$\epsilon_b = \frac{\sum_{i: y_i \ne f_b(x_i)} w_i^{(b)}}{\sum_i w_i^{(b)}}$


$c_b = \frac{1}{2}\log\left(\frac{1-\epsilon_b}{\epsilon_b}\right)$


$w_i^{(b+1)} = w_i^{(b)} \exp\left(-c_b y_i f_b(x_i)\right)$


$F(x) = \mathrm{sign}\left(\sum_{b=1}^{B} c_b f_b(x)\right)$

 

이 식의 의미는 오류율이 낮은 stump일수록 더 큰 모델 가중치 $C_b$ 를 받고

오분류된 샘플은 다음 단계에서 더 큰 학습 비중을 갖게 된다는 것입니다.

AdaBoost를 손실 함수 관점에서 보면

지수 손실(exponential loss)을 순차적으로 줄여 나가는 과정으로 해석할 수 있습니다.

그래서 단순히 “가중치를 크게 준다”는 설명보다

오류가 큰 샘플 쪽으로 목적함수를 기울이는 방식이라고 이해하면 더 정확할 것 같습니다.

 


Gradient Boosting Machine

 


GBM은 AdaBoost보다 더 일반적인 형태의 부스팅입니다. 

현재 모델이 남긴 오차, 즉 residual 또는 손실 함수의 negative gradient를 

다음 트리가 학습하도록 만듭니다.

GBM의 핵심은 “현재 모델이 틀린 방향을 따라가며 조금씩 보정한다”는 점입니다. 

첫 번째 모델은 보통 전체 평균처럼 아주 단순하게 시작하고

이후 트리들이 순서대로 residual을 줄이는 방향으로 더해집니다.

대표 수식은 아래처럼 쓸 수 있습니다.


$r_{ib} = -\left[\frac{\partial L(y_i, F(x_i))}{\partial F(x_i)}\right]_{F = F_{b-1}}$


$\gamma_{jb} = \arg\min_{\gamma} \sum_{x_i \in R_{jb}} L\left(y_i, F_{b-1}(x_i) + \gamma\right)$


$F_b(x) = F_{b-1}(x) + \nu \sum_{j=1}^{J_b} \gamma_{jb} I(x \in R_{jb})$

 

제곱오차 손실을 쓴다면 residual은 사실상 $r_i = y_i - \hat{f}(x_i)$ 와 같은 의미가 됩니다.

또 $nu$는 learning rate로, 각 트리가 현재 모델에 얼마나 강하게 반영될지를 조절해 과적합을 완화합니다.

 

GBM에서 꼭 같이 봐야 하는 하이퍼파라미터는 아래 셋입니다.

  • n_estimators: 트리 개수
  • learning_rate: 각 트리의 기여도
  • max_depth: 개별 트리 복잡도

 

XGBoost와 LightGBM

 


XGBoost는 GBM을 더 빠르고 강건하게 만든 개선형입니다. 

핵심은 손실 함수에 정규화 항을 추가해 과적합을 줄이고 split finding을 더 효율적으로 수행한다는 점입니다.

XGBoost의 정규화 형태는 아래처럼 정리할 수 있습니다.


$\Omega(f) = \gamma T + \frac{1}{2}\lambda c^2$

여기서 T는 terminal node 수, c는 각 노드의 가중치를 뜻합니다. 

즉, XGBoost는 트리를 더 많이 만들고 더 복잡하게 키우는 방향이 아니라

필요한 만큼만 쓰도록 비용을 부과하는 방식으로 일반화를 개선합니다.

LightGBM은 대용량 데이터에서 속도를 더 끌어올리는 데 초점이 맞춰진 부스팅 계열입니다. 

이를 위해 gradient가 작은 샘플 일부를 덜 보는 GOSS와

서로 배타적인 피처를 묶는 EFB를 사용해 계산량을 줄입니다.

즉, LightGBM은 “모든 데이터를 매번 다 보지 않고도 중요한 정보는 최대한 유지하자”는 

발상으로 이해하면 좋을 것 같습니다. 

 

부스팅 계열을 한 줄로 요약하면, 

GBM은 residual 기반의 일반형, XGBoost는 정규화와 효율성 강화형, LightGBM은 대용량·고속 학습 최적화형입니다.

추가로 부스팅 계열 요약에서는 CatBoost도 함께 대표 알고리즘으로 언급됩니다. 

CatBoost는 특히 범주형 변수 처리에 강점을 가지는 부스팅 계열로 실무에서 자주 같이 비교됩니다.

 


스태킹과 해석 가능성

 


스태킹은 서로 다른 유형의 모델들을 결합해

그 예측값 자체를 새로운 입력으로 삼는 meta model을 학습하는 방식입니다.

즉, base model이 1차 예측을 만들고, meta model이 그 예측들을 다시 조합해 최종 답을 만듭니다.

스태킹이 중요한 이유는 bagging처럼 같은 계열 모델만 반복하지 않아도 되고

boosting처럼 하나의 오류 보정 흐름에 묶이지도 않기 때문입니다.

예를 들어 Random Forest, GBM, SVM처럼 서로 다른 성격의 모델을 base layer에 두고

그 위에 로지스틱 회귀나 선형 회귀 같은 단순한 meta model을 얹을 수 있습니다.

다만 스태킹은 데이터 누수에 매우 민감하기 때문에

CV stacking처럼 교차검증 기반의 out-of-fold prediction을 사용해 meta model을 학습하는 방식이 중요합니다.

이 구조를 잘 지키면 stacking은 분산 감소뿐 아니라 편향 감소에도 도움을 줄 수 있습니다.

앙상블을 실제로 쓰다 보면 “성능은 좋은데 왜 그렇게 예측했는지 모르겠다”는 문제가 생깁니다.

그래서 부록에서 다루는 XAI도 함께 중요해지며, 대표적으로 LIME과 SHAP이 소개됩니다.

LIME은 특정 샘플 주변에서 블랙박스 모델을 로컬 선형 모델로 근사해 설명하는 방법입니다. 

빠르고 직관적이지만 주로 개별 샘플 설명에 초점이 맞춰져 있습니다.

SHAP은 게임이론의 Shapley value를 바탕으로 각 피처의 기여도를 공정하게 분배하는 방식입니다. 

이 방법은 개별 샘플 설명뿐 아니라 전체 모델 수준의 변수 중요도도 함께 볼 수 있다는 점에서 

더 일반적인 해석 도구로 쓰입니다.