본문 바로가기
Computer Science/Machine Learning

앙상블-배깅 (구현)

by BaekDaBang 2024. 6. 11.

예측기의 성능을 향상시키기 위해 여러 개의 훈련 데이터셋 각각을 이용하여 학습시킨 예측기를 결합하여 예측하는 방법을 배깅(Bagging)방식

배깅방식은 특히 가지치기가 이루어지지 않은 결정트리와 같이 훈련데이터셋의 훈련샘플의 작은 변화에 민감하게 영향을 받는 예측기들을 개선할 때 유용한 방식 

회귀문제에 대한 결정트리 예측기의 경우를 예로 들어 배깅방식을 설명하면 다음과 같다. 
훈련데이터셋 $\mathcal D$가 어떤 분포를 따르는 랜덤집합이라하고, $\mathcal D_1,\cdots,\mathcal D_n$가 동일한 분포에 iid라 하자. 각 $\mathcal D_i\, (1\le i \le n)$를 훈련데이터셋으로 학습시킨 예측기를 $g_{\mathcal D_i}\, (1\le i \le n)$이라 할 때, $$g_{\rm{avg}}(\mathbf x) = \dfrac 1 n \sum_{i=1}^n g_{\mathcal D_i}(\mathbf x)$$와 같이 예측기 $g_{\rm{avg}}$를 정의하면 큰 수의 법칙에 따라 예측기 $g_{\rm avg}$는 $n$이 커질 때 $g^*:=\rm{E}(g_{\mathcal D})$로 수렴하게 된다. 이때, 아래 정리에서 알 수 있듯이 서로 다른 훈련데이터셋으로 학습시킨 예측기의 평균값으로 예측을 하면 보다 나은 예측기를 구성할 수 있다. 

이 때 현실적으로 동일한 분포 iid를 따르는 여러 개의 훈련데이터셋 $\mathcal D_1,\cdots,\mathcal D_n$ 을 얻는 것이 어려움.  이를 극복하기 위해 $m$개의 훈련샘플로 이루어진 하나의 훈련데이터셋이 주어질 때, 이 훈련데이터셋에서 $m$개의 훈련샘플을 복원추출로 뽑는 과정을 $n$번 반복하여 랜덤 훈련데이터셋 $\mathcal D_1^*,\cdots, \mathcal D_n^*$을 구성하고    
$$ g_{bag}(\mathbf x)= \dfrac 1 n \sum_{i=1}^n g_{\mathcal D_i^*}(\mathbf x)$$
와 같이 예측기를 구성하는 것을 부트스트랩을 통해 종합한(bootstrapped aggregated) 예측기 또는 bagged 예측기라고 부른다.

# bag 예측기 구성 (500개의 예측기 구성)

n_estimators = 500 
bag = np.empty((n_estimators), dtype=object)

for i in range(n_estimators):

    ####### Empty Module.8 #######
    # 복원 추출을 이용하여 랜덤한 훈련 데이터셋 정의 (bootstrap)
    ids = np.random.choice(len(X_train), size=len(X_train), replace=True)  # np.random.choice 이용하여 인덱스 먼저 정의, 복원 추출로 진행, size는 len(X_train)만큼 샘플링
    X_boot = X_train[ids]                      # 인덱스 이용하여 데이터 샘플링
    y_boot = y_train[ids]                      # 인덱스 이용하여 데이터 샘플링
    ##############################

    bag[i] = DecisionTreeRegressor()
    bag[i].fit(X_boot, y_boot)
    
####### Empty Module.9 #######
yhatbag = np.zeros(len(X_test))

for i in range(n_estimators):
    yhatbag += bag[i].predict(X_test)

yhatbag /= n_estimators                          # 500개의 예측기를 이용하여 yhatbag 생성 반복문 이용하거나 np의 mean 함수 사용할 것
##############################

MSE_bagging = np.mean(np.power(yhatbag - y_test, 2))