Bagging (Bootstrap Aggregating)¶
논문 정보¶
| 항목 | 내용 |
|---|---|
| 제목 | Bagging Predictors |
| 저자 | Leo Breiman |
| 학회/저널 | Machine Learning |
| 연도 | 1996 |
| 링크 | https://link.springer.com/article/10.1023/A:1018054314350 |
개요¶
문제 정의¶
고분산 (High Variance) 모델의 문제:
- 훈련 데이터가 조금만 바뀌어도 모델이 크게 달라짐
- 과적합 경향
- 불안정한 예측
핵심 아이디어¶
"여러 번 샘플링하고, 여러 모델 학습 후, 결합하면 분산이 줄어든다"
독립적인 모델 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 중복)
포함 확률¶
각 샘플이 부트스트랩에 포함되지 않을 확률:
약 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\)일 때:
- \(\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