Stacking (Stacked Generalization)¶
논문 정보¶
| 항목 | 내용 |
|---|---|
| 제목 | Stacked Generalization |
| 저자 | David H. Wolpert |
| 학회/저널 | Neural Networks |
| 연도 | 1992 |
| 링크 | https://www.sciencedirect.com/science/article/abs/pii/S0893608005800231 |
개요¶
핵심 아이디어¶
"여러 모델의 예측을 입력으로 받아, 메타 모델이 최종 예측을 학습한다"
Level 0 (Base Learners): Level 1 (Meta Learner):
Input X ──┬──► Model 1 ──► pred_1 ──┐
│ │
├──► Model 2 ──► pred_2 ──┼──► Meta Model ──► Final Prediction
│ │
└──► Model 3 ──► pred_3 ──┘
Voting과의 차이¶
| 특성 | Voting | Stacking |
|---|---|---|
| 결합 방식 | 단순 평균/투표 | 학습된 가중치 |
| 모델 간 상호작용 | 없음 | 메타 모델이 학습 |
| 유연성 | 낮음 | 높음 |
| 과적합 위험 | 낮음 | 있음 (교차 검증 필요) |
Stacking 알고리즘¶
기본 구조¶
Algorithm: Stacking
Input: 학습 데이터 (X, y), 기반 학습기 {L_1, ..., L_K}, 메타 학습기 L_meta
Output: 스택 앙상블 모델
# Phase 1: 기반 학습기 훈련 (with cross-validation)
for each base learner L_k:
for each fold i in K-fold:
# i번째 fold 제외하고 학습
L_k.fit(X_train_i, y_train_i)
# i번째 fold 예측 (out-of-fold)
predictions_i = L_k.predict(X_val_i)
# 전체 데이터에 대한 out-of-fold 예측
meta_features_k = concatenate(predictions_i for all i)
# Phase 2: 메타 학습기 훈련
meta_X = stack(meta_features_1, ..., meta_features_K) # (n_samples, K)
L_meta.fit(meta_X, y)
# Phase 3: 최종 학습기 재훈련 (전체 데이터로)
for each base learner L_k:
L_k.fit(X, y)
return (L_1, ..., L_K, L_meta)
교차 검증의 중요성¶
왜 Out-of-Fold 예측이 필요한가?
잘못된 방법 (정보 누출):
X_train ──► Model ──► pred_train ──► Meta Model
└─────────────────────────────────────┘
동일 데이터로 학습 + 예측 = 과적합!
올바른 방법 (Out-of-Fold):
X_train ──┬── Fold 1,2,3 학습 ──► Fold 4 예측 ──┐
├── Fold 1,2,4 학습 ──► Fold 3 예측 ──┼──► Meta Model
├── Fold 1,3,4 학습 ──► Fold 2 예측 ──┤
└── Fold 2,3,4 학습 ──► Fold 1 예측 ──┘
학습에 사용되지 않은 데이터로 예측 = 일반화 보장
scikit-learn 구현¶
StackingClassifier¶
from sklearn.ensemble import StackingClassifier, RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
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.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
# 데이터
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)
# 기반 학습기 (다양한 유형)
base_learners = [
('rf', RandomForestClassifier(n_estimators=100, random_state=42)),
('svc', make_pipeline(StandardScaler(), SVC(probability=True, random_state=42))),
('knn', make_pipeline(StandardScaler(), KNeighborsClassifier(n_neighbors=5))),
('dt', DecisionTreeClassifier(max_depth=5, random_state=42))
]
# 메타 학습기
meta_learner = LogisticRegression(max_iter=1000)
# Stacking
stacking = StackingClassifier(
estimators=base_learners,
final_estimator=meta_learner,
cv=5, # 내부 교차 검증 폴드 수
stack_method='auto', # 'auto', 'predict_proba', 'decision_function', 'predict'
passthrough=False, # True면 원본 특성도 메타 학습기에 전달
n_jobs=-1
)
stacking.fit(X_train, y_train)
# 평가
print(f"Stacking Test Accuracy: {stacking.score(X_test, y_test):.4f}")
# 개별 모델과 비교
for name, model in base_learners:
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
print(f"{name}: {score:.4f}")
StackingRegressor¶
```python from sklearn.ensemble import StackingRegressor from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor from sklearn.linear_model import Ridge, Lasso, ElasticNet from sklearn.svm import SVR from sklearn.datasets import fetch_california_housing from sklearn.metrics import mean_squared_error, r2_score import numpy as np