5 minute read

Ensemble

Introduction

앙상블 학습이란, 여러가지 모델을 이용하여 대중의 지혜를 얻는 모델이라고 할 수 있다.

앙상블 기법에는 여러가지가 있는데, 배깅 , 부스팅, 스태킹 등이 존재한다.

이러한 앙상블 기법은 새로운 데이터 셋으로 새롭게 학습시키는 모델들을 병렬적으로 이용하거나, 한 데이터 셋에 대하여 그 데이터 셋을 학습시키고 부족한 부분을 또 학습시키거나, 모델의 학습 결과를 추가적인 Feature로 인지하여 학습을 시킨다던지 하는 여러가지 방식으로 진행이 된다.

간단하게 앙상블을 하는 기법으로는 투표 방식이 있다.

이러한 투표 방식은 모델 A,B,C가 있다고 할 때 각 모델의 결과값을 취합하여 다수결 원칙에 맞는 결과를 최종적으로 보여주는 것이다.

이러한 투표 방식 hard, soft 두 가지로 나뉘어지는데 대부분 확률에 초점을 맞추기 때문에 soft voting 을 선호한다.

Random Forest


그림 1. RandomForest

Random Forest의 기본적인 아이디어는 간단한 트리 기반의 모델을 각기 성질이 다른 샘플들로 학습을 시켜 이 결과를 토대로 최적의 결과를 도출한다는 것이다.

우선 Random forest에선 Bootstrap aggregation 으로 나눠주는데 해당 과정은 첫번째로 중복을 포함하여 원래 데이터 수 N개 만큼 Sampling 을 한다. (Bootstrap)

여기서 이렇게 샘플링이 되면 통계적으로 한번도 선택되지 않는 데이터가 존재할 수 있는데 그 확률은 $P = (1 - \frac{1}{N})^N = \lim (1-\frac{1}{N})^N = \exp(-1)$ 이 되며 이러한 데이터는 Out of bag 데이터라고 한다.

따라서 생각보다 많은 데이터 셋이 한번도 뽑히지 않을 수 있는데 이러한 데이터들은 차후 Random Forest의 검증에 사용되게 된다.

이 과정을 거치게 되면 Aggregating을 진행하는데, 해당 과정은 여러개의 단일 트리 모델에서 예측한 결과를 취합하는 과정이다.

이 과정은 앞서 말한 voting 과정과 비슷하다. 예를 들어 N개의 모델 중 가장 많이 예측한 것을 출력하거나($argmax_i(\sum_j ^N I(\hat{y}) , I \in {0,1}$) ) 결과값의 확률이 가장 큰 예측값을 출력하거나 ($argmax(\frac{1}{b}\sum P(y = i))$) 와 같이 여러 방법으로 모델 결과 값을 취합하게 된다.

Random Forest 는 앞서 말한 이 두 과정 (Bootstrap Aggregation) 을 거치며 만들어지게 된다.

python 에서는 간단한 코드 한 줄 구현으로 Random Forest 모델을 만들 수 있다.

from sklearn.ensemble import RandomForestClassifier
rnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, random_state=42)
rnd_clf.fit(X_train, y_train)

y_pred_rf = rnd_clf.predict(X_test)

해당 모델의 Param 에서 n_estimators 는 몇 개의 추정기를 가질지, max_leaf_nodes는 각 트리가 몇개의 리프노드를 가질지 정하는 것이다.

이러한 Random Forest는 한 데이터 셋에서 진행되는 예측기이기 때문에 예측기 간의 상관관계가 높을 수 있으며 좋은 앙상블 성능을 기대하지 못할 수 있다.

따라서 Random Forest를 사용할 때 Random subspace 즉, 일부 변수만을 사용하는 것으로 각 추정기 간의 상관관계를 조금이나마 줄일 수 있다. (ex ) max_features = 0.5)

Random Forest는 테스트 데이터 세트 외에도 자체적으로 Out of bag 데이터를 통해 해당 모델을 검증하거나, 특성 중요도를 파악할 수 있다.

모델 검증에 대한 내용은 매우 간단하고 직관적인 것이므로 넘어가서, 어떻게 특정 변수의 중요도를 나타낼 수 있는지 알아보자.

우선 과정은 아래와 같다.

  • 각 Bootstrap데이터 셋에서 생성된 Tree에서 OOB error 계산.
  • 1의 Tree 에서 특정 변수($x_i$) 값을 뒤섞은 후 데이터 집합에 대해 OOB error 계산 (sample의 변수가 뒤섞임)
  • $ d = \vert e_i - r_i \vert (i = 1,2,\dots , )$ $\hat{d} = \frac{1}{t}\sum_{i=1}^t d_i, \ \ s_d^2 = \frac{1}{t-1}(d_i - \hat{d})^2$ 을 구한다.
    • 이 과정을 좀 더 깊게 살펴보자면, 각 $e_i $들은 2번 과정에서의 error 이며, $r_i $ 는 기존 tree 에서의 error 이다.
    • 변수를 섞은 후 나온 error를 모두 구한 후 $s_d$ 는 모든 Tree 에서 나온 표본 오차이다.
    • 다시말해 $t$ 개의 tree 에 대하여 전체 오차를 구한 후 변수를 섞은 후 다시 모든 Tree에 대한 오차를 구한다.
  • $v_i = \frac{\hat{d}}{s_d}$ 를 구하여 해당 변수의 중요도를 구한다.

이 과정에서 나온 $v_i$ 의 식은 변수를 바꾼 후 나온 오차 $d$ 만을 본다는 뜻이 아닌, 해당 오차와 더불어 각각의 tree 에서의 $d$ 값의 편차가 크다면 그 편차 만큼의 Penalty 를 주겠다는 뜻이다.

이렇게 페널티를 주는 이유는 해당 변수를 바꿈으로써 나온 에러 값이 이리저리 튀게 된다면 전반적인 모든 Tree에서 중요도가 얼마나 되는지의 흐름을 파악하기 어렵기 때문이다.

Boosting

부스팅 또한 Ensemble의 일종이다.

Boosting의 경우 여러개의 약한 학습기를 연결하여 강한 학습기를 만드는 Ensemble기법 중 하나인데, 쉽게 생각하자면 예측이 잘 안된 부분을 집중적으로 파고들어 계속 예측하는 것이라고 할 수 있다.

이러한 부스팅 중 대표적으로 AdaBoosting, Gradient Boosting 에 대해 살펴보자.

AdaBoosting


그림 2. AdaBoost

Adaboost를 직관적으로 이해한다면, 예측 후 오답에 대해 더 가중치를 주어 새로운 예측을 하게 만드는 것이다.

위 그림의 경우 Box2에서 몇몇 + 기호가 커짐을 볼 수 있다. 이 의미는 이들을 좀 더 집중적으로 파악하겠다 (Loss부여의 정도를 좀 더 강하게 하겠다)는 의미라고 할 수 있다.

Adaboost에는 기본적인 두 수식이 있다.

  • $L_j = \frac{\sum_{i=1}^n w_i (y_i \neq h_j(x))}{\sum_{i=1}^n w_i}$
  • $\alpha_j = log(\frac{1-L_j}{L_j})$

우선 AdaBoost에서는 모든 데이터에 대해 가중치가 부여되어있으며 해당 가중치가 각 $w_i$ 이다.

$L_j$ 의 분자를 보게 된다면, $h_j(x)$ 란 모델에서 예측한 $y$ 값이며, 분모는 모든 데이터 셋의 가중치이다. 따라서 여기서 $L_j$ 는 전체 가중치 중에 예측값과 실제 라벨이 다른 데이터들의 가중치만을 집중해서 보겠다는 것이다.

$\alpha_j$ 는 각각 $w_i$ 가 업데이트 될 때 참조하는 수식으로 이 것이 실질적인 가중치라고 할 수 있으며 오분류된 샘플의 가중치를 증가하는 데에 사용한다. 만약 샘플이 잘 분류 되었다면 $\alpha_j$ 만큼 업데이트 되지 않고 그대로 가중치를 유지한다.


그림 3. L,alpha 수식

해당 그림은 $L$(x축) 과 $\alpha$(y축) 의 관계식 그림이다. 해당 그림에서 알 수 있듯이 $L_j$ 값이 0에 수렴한다면 즉, 잘못 예측한 샘플이 매우 적다면 $\alpha $ 는 더욱 커지게 되며 잘못 예측한 샘플(적은 수) 에 더 많은 가중치를 부여하게 된다.

Adaboost의 진행 과정을 한번 살펴보자.

  • 초기 가중치는 모든 data에 $\frac{1}{n}$ 으로 똑같이 부여한다.
    • ex ) 10개 중 3개 오분류 $\alpha_1 = log(\frac{1-0.3}{0.3}) = 0.37$
    • $w_c(correct) = 0.1\exp(0.37 \times 0)$ $w_{nc}(not \ correct) = 0.1\exp(0.37 \times 1)$
  • 이후 조정된 가중치를 통해 또 $L_2$ 를 구하여 가중치를 계속하여 Update( 이 때 새로운 $L_1$ 로 update된 가중치가 새로운 예측기에 들어가는 것)

이렇게 예측기가 지정된 수에 도달하거나 완벽한 예측기가 만들어지게 되면 훈련이 종료되게 된다.

이후 Adaboost는 모든 예측기의 예측을 계산하며, 각 예측기의 클래스 별 가중치를 모두 더한 후 가중치 합이 가장 큰 클래스를 예측 결과로 내놓는다.

Gradient Boosting

Adaboost와 GB는 가중치를 학습시키느냐, 오차를 학습시키느냐의 차이가 존재한다.

GB와 같은 경우는 좀 더 직관적인 이해가 가능하다. 해당 모델은 잔여 오차에 대해서 지속적으로 학습하는 모델이며, 따로 샘플에게 가중치를 부여하는 모델은 아니다.

해당 모델은 Tree 기반의 모델이며, 각 트리에서 놓친 부분이 다음 트리에 들어가게 된다.

  • 처음 기존 Tree가 예측값 $\hat{y}$를 만든다.

  • $y - \hat{y} $ 가 이후 Tree에 들어가게 된다.(각 Tree에서 놓친 Residual 학습)

    • Gradient의 미분 (MSE loss) : $L = \frac{1}{2}\sum (y_i -f(x_i)^2)$
    • $\frac{\partial L}{\partial f(x)} = -(y_i - f(x_i))$ 이 것이 0이되는 지점 즉, 이 것의 최솟값을 구하게 된다면?

다음 Step은 GB의 학습 스탭인데 생각보다 매우 간단한 방향으로 이어지게 된다.

이후 최종적인 모델은 각 예측기를 모두 더한 형태의 꼴로 나타내어지는데, 밑에 보이는 그림과 같이 최종적인 모델이 생기게 된다.


그림 4. GB