본문 바로가기

파이썬/머신러닝

에이다부스트와 그라디언트부스팅 기본 개념과 코드, 부스팅과 배깅의 차이

이번 포스팅에서는 앙상블 학습 두번째, 부스팅에 대해 알아보자.

다른 앙상블 학습인 배깅과 랜덤포레스트는 아래 링크에서 확인!

 

 

2021.06.21 - [파이썬/머신러닝] - 배깅(bagging) 기본 개념과 예시, 사이킷런 BaggingClassifier

2021.06.19 - [파이썬/머신러닝] - 랜덤 포레스트 원리와 구현 사이킷런 예제로 코드 실습해보기

 

 

부스팅 기본 개념, 배깅과의 차이

출처:  Medium (Boosting and Bagging explained with examples)

 

부스팅은 weak learner 여러개를 연결해 strong learner를 만드는 앙상블 기법이다.

배깅은 훈련 세트에서 중복을 허용하여 샘플링해서 여러 개의 분류기를 만들어 분류 모델의 경우 최빈값을, 회귀 모델의 경우 평균값을 최종 예측값으로 사용하는 병렬 학습이다.

 

 

반면 부스팅은 한번에 여러개의 예측기를 만드는 것이 아니라, 이전 예측기의 성능을 보완하는 새로운 예측기를 만들면서 정확도를 높여나간다.

 

 

한번 학습이 끝나면 이전 모델이 과소적합했던 (=정답을 맞추지 못했던) 훈련 샘플에 가중치를 더 높게 주어서 학습하기 어려운 샘플을 더 잘 맞출 수 있도록 하는 것이 부스팅이다.

 

 

배깅에 비해서 성능이 좋다는 장점이 있지만 속도가 느리고 오버피팅 가능성이 있다. 배깅과 부스팅 중 어느 것을 쓸 것인가는 상황에 따라서 다르다.

 

 

에이다 부스트

 

부스팅도 여러가지가 있는데 가장 많이 쓰이는 것이 에이다부스트(Adaptive Boosting)와 그레디언트 부스팅(Gradient Booting)이다. 먼저 에이다 부스트부터 알아보자.

 

 

출처: StatQuest

 

한개의 노드와 두개의 리프로 이루어진 트리를 stump라고 한다. 에이다부스트는 여러 개의 stump를 합쳐서 최종 성능 결과값을 내놓는데 이 때 각각의 stump의 가중치는 모두 다르다. 앞서 말한 대로 분류가 잘못된 샘플의 가중치가 크다.

 

 

에이다 부스트의 알고리즘은 간단하다.

 

1. 각 샘플의 가중치는 초기에 1/m으로 초기화

2. 첫번째 예측기가 학습되고 가중치가 적용된 에러율 r1이 훈련set에 대해 계산

3. 샘플의 가중치 업데이트 (잘못된 분류 샘플의 가중치가 커짐)

4. 모든 샘플의 가중치를 정규화

5. 새 예측기는 업데이트 된 가중치를 사용해서 훈련

6. 1-5의 과정을 반복하다가 지정된 예측기 수에 도달하거나 완벽한 예측기가 만들어지면 중단

 

 

사이킷런의 make_moons 데이터셋으로 결정트리를 기반으로 하는 AdaboostClassifier를 훈련시켜보자.

from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

X, y = make_moons(n_samples=500, noise=0.30, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), n_estimators=200, algorithm='SAMME.R', learning_rate=0.5)
ada_clf.fit(X_train, y_train)

y_pred = ada_clf.predict(X_test)
accuracy_score(y_test, y_pred)
>>>0.896

 

base_estimator로 결정트리를 사용했는데 이 때 max_depth를 1로 설정했다.

즉, 깊이가 1인 아주 얕은 결정트리(stump)를 200개 사용해서 에이다부스트 분류기를 훈련시키는 코드이다.

 

 

사용하는 base_estimator에 predict_proba( ) 메서드가 있다면 사이킷런의 AdaboostClassifier는 알고리즘으로 'SAMME.R'을 사용한다. 클래스가 2개인 경우에는 SAMME 알고리즘을 사용하는데 일반적으로 SAMME.R이 SAMME보다 빠르고 성능도 좋다.

 

 

그라디언트 부스팅

 

그래디언트 부스팅도 에이다부스트처럼 이전까지의 오차를 보정하도록 순차학습을 한다. 다만 에이다부스트처럼 반복할 때마다 샘플의 가중치를 수정하는 것이 아니라, 이전 예측기가 만든 잔여 오차(residual error)에 새로운 예측기를 학습시킨다.

 

 

아주 간단한 모델 A로 y를 예측하고 남은 잔차로 다시 다음 모델 B를 학습시켜서 y를 예측한다. 이 과정을 계속 반복하다보면 잔차는 계속 줄어들게 된다. 다만 오버피팅의 문제가 있어서 더 빠르고 과적합이 적은 Light GBM을 사용하는 경우가 많다.

 

from sklearn.ensemble import GradientBoostingRegressor
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

X_train, X_val, y_train, y_val = train_test_split(X, y, random_state=42)

gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=120)
gbrt.fit(X_train, y_train)

#최적의 트리 수를 찾기 위해 각 훈련단계 별 검증오차 측정
errors = [mean_squared_error(y_val, y_pred)
          for y_pred in gbrt.staged_predict(X_val)]

best_n_estimators = np.argmin(errors)+1

gbrt_best = GradientBoostingRegressor(max_depth=2, n_estimators=best_n_estimators)
gbrt_best.fit(X_train, y_train)

print(gbrt.score(X_test, y_test))
print(gbrt_best.score(X_test, y_test))
>>>0.7151736174369571
>>>0.7212655703427918

 

데이터셋은 에이다부스트와 마찬가지로 make_moons 데이터셋을 사용했다.

 

 

그냥 GradientBoostingRegressor에 피팅시켰을 때 test set의 정확도는 71.5%이다. 각 단계별로 검증오차를 측정해서 최적의 트리 수를 찾아서 다시 회귀 모델에 적합을 시키면 test set 정확도는 72.1%로 미미하게나마 성능이 개선되었다.