콘텐츠로 이동

Bagging (Bootstrap Aggregating)

논문 정보

항목 내용
제목 Bagging Predictors
저자 Leo Breiman
학회/저널 Machine Learning
연도 1996
링크 https://link.springer.com/article/10.1023/A:1018054314350

개요

문제 정의

고분산 (High Variance) 모델의 문제:

  • 훈련 데이터가 조금만 바뀌어도 모델이 크게 달라짐
  • 과적합 경향
  • 불안정한 예측

핵심 아이디어

"여러 번 샘플링하고, 여러 모델 학습 후, 결합하면 분산이 줄어든다"

\[\text{Var}\left(\frac{1}{n}\sum_{i=1}^{n} X_i\right) = \frac{\sigma^2}{n}\]

독립적인 모델 n개의 평균은 분산을 \(1/n\)로 감소시킴.

Bootstrap Sampling

개념

원본 데이터에서 복원 추출로 같은 크기의 샘플 생성:

Original:  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Bootstrap 1: [2, 5, 5, 1, 8, 3, 10, 2, 7, 3]  (5, 2, 3 중복)
Bootstrap 2: [9, 1, 4, 4, 6, 8, 2, 1, 9, 3]  (9, 4, 1 중복)
Bootstrap 3: [7, 3, 6, 1, 2, 5, 8, 4, 1, 6]  (1, 6 중복)

포함 확률

각 샘플이 부트스트랩에 포함되지 않을 확률:

\[P(\text{not selected}) = \left(1 - \frac{1}{n}\right)^n \approx \frac{1}{e} \approx 0.368\]

63.2% 의 데이터만 각 부트스트랩에 포함됨.

나머지 36.8% 는 Out-of-Bag (OOB) 샘플로 검증에 사용 가능.

Bagging 알고리즘

Pseudocode

Algorithm: Bagging

Input: 학습 데이터 D = {(x_i, y_i)}, 기반 학습기 L, 앙상블 크기 B
Output: 앙상블 모델 H

for b = 1 to B:
    # Bootstrap sampling
    D_b = Bootstrap(D, n)  # n개 복원 추출

    # Train base learner
    h_b = L(D_b)

# Aggregation
for classification:
    H(x) = majority_vote({h_1(x), ..., h_B(x)})

for regression:
    H(x) = (1/B) * sum_{b=1}^{B} h_b(x)

return H

시각화

Original Dataset D
        ├──Bootstrap──► D_1 ──► Model_1 ──┐
        │                                  │
        ├──Bootstrap──► D_2 ──► Model_2 ──┼──► Aggregate ──► Prediction
        │                                  │
        ├──Bootstrap──► D_3 ──► Model_3 ──┤
        │                                  │
        └──Bootstrap──► D_B ──► Model_B ──┘

분산 감소 효과

이론적 분석

개별 모델의 예측: \(h_1(x), h_2(x), ..., h_B(x)\)

앙상블 예측: \(\bar{h}(x) = \frac{1}{B}\sum_{b=1}^{B} h_b(x)\)

모델 간 상관계수가 \(\rho\)일 때:

\[\text{Var}(\bar{h}) = \rho \sigma^2 + \frac{1-\rho}{B}\sigma^2\]
  • \(\rho = 1\) (완전 상관): \(\text{Var}(\bar{h}) = \sigma^2\) (감소 없음)
  • \(\rho = 0\) (독립): \(\text{Var}(\bar{h}) = \frac{\sigma^2}{B}\) (최대 감소)

핵심: 모델 간 상관관계를 낮추는 것이 중요

Random Forest가 Bagging보다 나은 이유

Random Forest는 특성 무작위 선택으로 \(\rho\)를 추가 감소시킴.

scikit-learn 구현

BaggingClassifier

from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score, classification_report

# 데이터
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Bagging with Decision Tree
bagging = BaggingClassifier(
    estimator=DecisionTreeClassifier(),
    n_estimators=100,          # 앙상블 크기
    max_samples=1.0,           # 각 부트스트랩 샘플 비율
    max_features=1.0,          # 각 모델의 특성 비율
    bootstrap=True,            # 복원 추출
    bootstrap_features=False,  # 특성 복원 추출 여부
    oob_score=True,            # OOB 점수 계산
    n_jobs=-1,
    random_state=42
)

bagging.fit(X_train, y_train)

# 평가
print(f"Train Accuracy: {bagging.score(X_train, y_train):.4f}")
print(f"Test Accuracy: {bagging.score(X_test, y_test):.4f}")
print(f"OOB Score: {bagging.oob_score_:.4f}")

# 단일 Decision Tree와 비교
single_tree = DecisionTreeClassifier(random_state=42)
single_tree.fit(X_train, y_train)
print(f"\nSingle Tree Test Accuracy: {single_tree.score(X_test, y_test):.4f}")

BaggingRegressor

from sklearn.ensemble import BaggingRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.datasets import fetch_california_housing
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

# 데이터
X, y = fetch_california_housing(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Bagging Regressor
bagging_reg = BaggingRegressor(
    estimator=DecisionTreeRegressor(max_depth=10),
    n_estimators=50,
    max_samples=0.8,      # 80% 샘플 사용
    max_features=0.8,     # 80% 특성 사용
    bootstrap=True,
    oob_score=True,
    n_jobs=-1,
    random_state=42
)

bagging_reg.fit(X_train, y_train)
y_pred = bagging_reg.predict(X_test)

print(f"RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}")
print(f"R2: {r2_score(y_test, y_pred):.4f}")
print(f"OOB R2: {bagging_reg.oob_score_:.4f}")

다양한 기반 학습기

from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression

# SVM Bagging (불안정한 모델에 효과적)
svm_bagging = BaggingClassifier(
    estimator=SVC(kernel='rbf', C=10),
    n_estimators=30,
    max_samples=0.7,
    n_jobs=-1
)

# KNN Bagging
knn_bagging = BaggingClassifier(
    estimator=KNeighborsClassifier(n_neighbors=5),
    n_estimators=30,
    max_features=0.5,  # 특성 샘플링
    n_jobs=-1
)

# 비교 평가
for name, clf in [('DT Bagging', bagging), 
                   ('SVM Bagging', svm_bagging), 
                   ('KNN Bagging', knn_bagging)]:
    clf.fit(X_train, y_train)
    print(f"{name}: {clf.score(X_test, y_test):.4f}")

Out-of-Bag (OOB) 평가

OOB 원리

각 샘플은 일부 모델에서만 학습에 사용됨:

Sample   Model_1  Model_2  Model_3  Model_4  ...  OOB Prediction
  1        O        X        O        X      ...  avg(M2, M4, ...)
  2        X        O        O        X      ...  avg(M1, M4, ...)
  3        O        O        X        X      ...  avg(M3, M4, ...)

O: 학습에 사용됨
X: OOB (학습에 미사용)

OOB 장점

  • 별도 검증 세트 불필요
  • 교차 검증 없이 일반화 성능 추정
  • 계산 효율적

OOB 활용

import numpy as np
import matplotlib.pyplot as plt

# n_estimators에 따른 OOB 오차 변화
n_estimators_range = range(10, 201, 10)
oob_errors = []

for n in n_estimators_range:
    bag = BaggingClassifier(
        estimator=DecisionTreeClassifier(),
        n_estimators=n,
        oob_score=True,
        random_state=42,
        n_jobs=-1
    )
    bag.fit(X_train, y_train)
    oob_errors.append(1 - bag.oob_score_)

plt.figure(figsize=(10, 5))
plt.plot(n_estimators_range, oob_errors, marker='o')
plt.xlabel('Number of Estimators')
plt.ylabel('OOB Error')
plt.title('OOB Error vs Number of Estimators')
plt.grid(True)
plt.savefig('bagging_oob.png', dpi=150)
plt.show()

print(f"Best n_estimators: {n_estimators_range[np.argmin(oob_errors)]}")

Pasting vs Bagging

기법 샘플링 방식 중복 sklearn
Bagging 복원 추출 있음 bootstrap=True
Pasting 비복원 추출 없음 bootstrap=False
# Pasting (복원 없이 샘플링)
pasting = BaggingClassifier(
    estimator=DecisionTreeClassifier(),
    n_estimators=100,
    max_samples=0.7,  # 70% 샘플 (중복 없이)
    bootstrap=False,  # Pasting
    n_jobs=-1
)

일반적으로 Bagging이 Pasting보다 다양성이 높아 성능이 좋음

Random Subspaces & Random Patches

Random Subspaces

특성만 무작위 샘플링:

# Random Subspaces (특성 샘플링만)
random_subspaces = BaggingClassifier(
    estimator=DecisionTreeClassifier(),
    n_estimators=100,
    max_samples=1.0,           # 전체 샘플 사용
    max_features=0.5,          # 50% 특성만 사용
    bootstrap=False,           # 샘플 중복 없음
    bootstrap_features=True,   # 특성 복원 추출
    n_jobs=-1
)

Random Patches

샘플과 특성 모두 무작위 샘플링:

# Random Patches
random_patches = BaggingClassifier(
    estimator=DecisionTreeClassifier(),
    n_estimators=100,
    max_samples=0.7,           # 70% 샘플
    max_features=0.7,          # 70% 특성
    bootstrap=True,            # 샘플 복원
    bootstrap_features=True,   # 특성 복원
    n_jobs=-1
)

언제 쓰나?

적합한 상황: - 고분산 모델 (Decision Tree, KNN 등) - 과적합 방지 필요 - 안정적인 예측 필요 - 병렬 처리 가능 환경

부적합한 상황: - 이미 안정적인 모델 (Linear Regression 등) - 고편향 모델 (Boosting이 더 적합) - 실시간 예측 (앙상블은 느림) - 해석 가능성 중요

Random Forest와의 관계

Random Forest = Bagging + Random Feature Selection

특성 Bagging Random Forest
샘플 Bootstrap Bootstrap
특성 전체 사용 무작위 부분집합
기반 모델 자유 선택 Decision Tree
상관관계 높음 낮음
성능 좋음 더 좋음

자세한 내용: Random Forest

관련 문서

주제 링크
앙상블 개요 README.md
Boosting boosting.md
Stacking stacking.md
Random Forest ../supervised/classification/random-forest.md

참고

  • Breiman, L. (1996). "Bagging predictors". Machine Learning.
  • Breiman, L. (2001). "Random forests". Machine Learning.
  • scikit-learn BaggingClassifier: https://scikit-learn.org/stable/modules/ensemble.html#bagging