アンサンブル学習は、複数のモデルを組み合わせて予測を安定させる考え方です。リハビリテーション研究では、FIM・歩行指標・検査値・画像由来特徴量など、多様な説明変数を同時に扱う場面があります。とはいえ、複雑に組み合わせればよいわけではなく、小標本では交差検証の設計と過学習の確認が中心になります。
本記事では、Bagging・Boosting・Stacking を対比します。単一の 決定木 から ランダムフォレスト や 勾配ブースティング へ進む前に、「なぜ複数モデルを組み合わせるのか」を整理します。 線形回帰、 正則化、 過学習と正則化 と比較しながら読むと、構造が掴みやすくなります。Stacking の out-of-fold 予測は 14·02 交差検証デモ、複雑モデルの過学習リスクは 14·01 過学習デモ で体感できます。
// 01 · LEARN OUTCOMESこの記事で学ぶこと
- Bagging、Boosting、Stacking の目的と違いを説明できるようになります。
- 分散低減とバイアス低減を、医療データの文脈で理解できます。
- 小規模リハ研究で、複雑なアンサンブルが過学習しやすい理由を整理できます。
- Pipeline と交差検証を使い、リーケージを避けた実装の型を確認できます。
// 02 · CONCLUSION先に結論
アンサンブルの魅力は、1 つのモデルの癖を弱められる点にあります。決定木は解釈しやすい一方でデータの揺らぎに敏感で、複数の木を作って平均すると予測のばらつきが小さくなります。これが Bagging の基本です[1]。
Boosting は少し違う発想です。前のモデルが間違えた症例を、次のモデルが重視する。弱いモデルを順に足し合わせていきます[2]。Stacking はさらに別で、ロジスティック回帰・木系モデル・SVM などの予測を、もう 1 つのモデルに渡して統合します[3]。
// 03 · FIGURE図で見るアンサンブル学習
Bagging は、同じ学習アルゴリズムを少しずつ違うデータで学習させる方法です。個々のモデルは少しずつ違う判断を下し、最終的には平均や多数決で予測します。深い決定木のように揺れやすいモデルで特に有用です。
Boosting は、モデルを順番に作っていきます。1 本目の木が外した症例を、2 本目はより重視する。残った誤差を次の木が補う、という流れです。退院時 FIM や歩行自立のように、非線形な関係がある表データでよく使われます。
Stacking は、異なる視点を持つモデルの「意見」を集める設計です。線形モデルは全体傾向を、木系モデルは非線形や交互作用を拾います。それらの予測値を、メタモデルが統合する。ただし、学習データで作った予測をそのまま使うとリーケージに近い楽観評価になるため、out-of-fold 予測が必須です。
// 04 · CLINICALリハ研究での使いどころ
回復期病棟の表形式データでは、年齢・発症からの日数・入院時 FIM・SIAS・併存疾患などを使います。Random Forest は分散を抑えた堅実な候補、Gradient Boosting は非線形関係を細かく拾う候補です。AUC だけでなく、Brier score と calibration も確認します。
脳卒中後の転倒予測を N=150 で検討する場面です。単一の深い木は、fold によって分岐構造が変わりやすくなります。Bagging は複数の木を平均し、予測の揺れを抑えます。ただし、症例数が少ない場合は外部検証なしに結論を強く書かない姿勢が必要です。
多施設の自宅退院予測では、施設差が予測に影響します。ロジスティック回帰・Random Forest・XGBoost の予測を、線形メタモデルで統合する設計が考えられます。この場合、GroupKFold で施設単位の汎化を見ます。Stacking のメタ特徴量は、必ず out-of-fold 予測で作ります。
歩行加速度・ウェアラブルセンサ・電子カルテ時系列では、通常パターンから外れたデータを探す場面があります。Isolation Forest はランダムな分割を多数作る方法で、Bagging 的な考え方と近く、03·11 の異常検知へつながります。
// 05 · THEORY仕組みを少しだけ数式で見る
Bagging: ブートストラップで平均する
Bagging は Bootstrap aggregating の略です。元データから重複を許してサンプルを取り、複数の学習データを作ります。それぞれでモデルを学習し、平均または多数決を取ります[1]。
f_hat(x) = (1 / B) * Σ f_b(x)
B : モデル数
f_b(x) : b 番目のモデルの予測
分類 : 多数決または平均確率
回帰 : 予測値の平均
Bagging が効きやすいのは、個々のモデルの分散が大きい場合です。深い決定木はその代表で、1 本だけだと症例の少しの違いで分岐が変わってしまいます。多数の木を平均すれば、その揺れが弱まります。
Boosting: 間違いを順番に補う
AdaBoost は、前のモデルが間違えた症例の重みを増やします[2]。次の弱学習器は、難しい症例をより重視します。Gradient Boosting は、損失関数を下げる方向に木を足していく考え方です。
err_t = Σ w_i * I(y_i != h_t(x_i)) / Σ w_i
alpha_t = 0.5 * log((1 - err_t) / err_t)
w_{t+1} = w_t * exp(alpha_t * I(y_i != h_t(x_i)))
直感的には、Boosting は「残った誤差を次のモデルが担当する」方法です。浅い木を少しずつ足すため、単純なモデルから複雑なモデルへ段階的に進みます。learning rate を小さくすると、学習はゆっくり進み、過学習を抑えやすくなる場合があります。
Stacking: 予測をもう一度学習する
Stacking は、複数のモデルの予測を新しい特徴量として使います[3]。ただし、同じデータで学習した予測をそのまま使うと、過度に良い結果が出てしまいます。fold 外の症例に対する予測を作っておく必要があります。
Step 1: fold 1 を検証用にして、fold 2-5 で base models を学習
Step 2: fold 1 に対する予測を保存
Step 3: これを全 fold で繰り返す
Step 4: out-of-fold 予測を meta features として使う
Step 5: meta model を学習する
医療データでは Stacking は魅力的に見えますが、症例数が十分でないとメタモデルまで含めて過学習します。特に N=100〜300 程度では、線形・正則化・単純な木系モデルとの比較が欠かせません。
// 06 · IMPLEMENTATIONPython 実装例
以下は教育用の仮想データです。実データで解析する場合は、個人情報保護・倫理審査・施設ルール・利用規約を先に確認します。前処理は Pipeline 内で行い、交差検証の各 train fold の中だけで fit します。全データで補完や標準化をしてから分割する流れは避けます。
import pandas as pd
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import StratifiedKFold, cross_validate, cross_val_predict
from sklearn.metrics import roc_auc_score, brier_score_loss
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier, AdaBoostClassifier, StackingClassifier
from sklearn.ensemble import RandomForestClassifier, HistGradientBoostingClassifier
# ------------------------------------------------------------
# 教育用の仮想データ: example_rehab_dataset.csv
# target は自宅退院あり=1 / なし=0 などを想定
# 実患者データでは、倫理審査・匿名化・施設規程を確認する
# ------------------------------------------------------------
df = pd.read_csv("example_rehab_dataset.csv")
target = "home_discharge"
features = [
"age", "days_from_onset", "fim_motor_admission",
"fim_cognition_admission", "sias_total", "nihss_total",
"tug_seconds", "bbs_total", "comorbidity_count",
"diagnosis", "ward", "sex"
]
X = df[features]
y = df[target].astype(int)
numeric_features = [
"age", "days_from_onset", "fim_motor_admission",
"fim_cognition_admission", "sias_total", "nihss_total",
"tug_seconds", "bbs_total", "comorbidity_count"
]
categorical_features = ["diagnosis", "ward", "sex"]
numeric_pipe = Pipeline(steps=[
("imputer", SimpleImputer(strategy="median")),
# Stacking の LogisticRegression も含めるため標準化する
("scaler", StandardScaler())
])
categorical_pipe = Pipeline(steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore"))
])
preprocess = ColumnTransformer(
transformers=[
("num", numeric_pipe, numeric_features),
("cat", categorical_pipe, categorical_features)
]
)
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
bagging = Pipeline(steps=[
("prep", preprocess),
("model", BaggingClassifier(
estimator=DecisionTreeClassifier(max_depth=None, min_samples_leaf=10),
n_estimators=200,
max_samples=0.8,
random_state=42,
n_jobs=-1
))
])
adaboost = Pipeline(steps=[
("prep", preprocess),
("model", AdaBoostClassifier(
estimator=DecisionTreeClassifier(max_depth=1, min_samples_leaf=20),
n_estimators=200,
learning_rate=0.05,
random_state=42
))
])
rf_base = RandomForestClassifier(
n_estimators=300,
min_samples_leaf=10,
random_state=42,
n_jobs=-1
)
gb_base = HistGradientBoostingClassifier(
max_iter=200,
learning_rate=0.05,
max_leaf_nodes=15,
random_state=42
)
stacking = Pipeline(steps=[
("prep", preprocess),
("model", StackingClassifier(
estimators=[
("logit", LogisticRegression(max_iter=2000, class_weight="balanced")),
("rf", rf_base),
("gb", gb_base)
],
final_estimator=LogisticRegression(max_iter=2000),
cv=5,
stack_method="predict_proba",
n_jobs=-1
))
])
models = {
"bagging_tree": bagging,
"adaboost_stump": adaboost,
"stacking": stacking
}
for name, model in models.items():
scores = cross_validate(
model, X, y, cv=cv,
scoring=["roc_auc", "neg_brier_score"],
n_jobs=-1,
return_train_score=False
)
auc = scores["test_roc_auc"]
brier = -scores["test_neg_brier_score"]
print(name)
print(f"AUC: {auc.mean():.3f} +/- {auc.std():.3f}")
print(f"Brier: {brier.mean():.3f} +/- {brier.std():.3f}")
# Stacking の概念確認: out-of-fold 予測を作る
# 実務ではこの OOF 予測を meta feature として扱う
base_for_oof = bagging
proba_oof = cross_val_predict(
base_for_oof, X, y,
cv=cv,
method="predict_proba",
n_jobs=-1
)[:, 1]
print("OOF AUC:", roc_auc_score(y, proba_oof))
print("OOF Brier:", brier_score_loss(y, proba_oof))
このコードでは、Bagging・AdaBoost・Stacking を同じ CV で比較します。StackingClassifier の内部でも CV が走るため、外側の cross_validate と合わせて評価の設計を明確にする必要があります。多施設データでは、StratifiedKFold ではなく GroupKFold を検討します。
// 07 · MYTHSよくある誤解
- 誤解: アンサンブルなら単一モデルより必ず良い
- 条件によります。小データでは、組み合わせるほど過学習する場合があります。線形モデルや正則化モデルと比較します。
- 誤解: Boosting は AdaBoost と同じ
- AdaBoost は代表的な Boosting です。Gradient Boosting・XGBoost・LightGBM・CatBoost は別の実装思想を持ちます。損失関数・正則化・欠測処理・カテゴリ変数の扱いが異なります。
- 誤解: Stacking はモデルを並べるだけ
- Stacking では out-of-fold 予測が中心です。学習済みモデルの訓練データ予測をそのまま使うと、評価が楽観的になります。メタモデルの学習データの作り方を Methods に書きます。
- 誤解: アンサンブルは解釈できない
- 単一木より読みにくくはなります。ただし、Permutation importance・PDP・ALE・SHAP などで部分的に説明できます。それでも因果効果とは区別します。
// 08 · WRITING論文 Methods で書くこと
医療予測モデルとして報告する場合は、モデル名だけでは不十分です。TRIPOD+AI では、データ・対象者・予測時点・アウトカム・前処理・モデル開発・検証・性能指標を透明に書くことが求められます[6]。PROBAST+AI では、バイアスのリスクと適用可能性を評価します[7]。
- 01Bagging、Boosting、Stacking のどれを使ったかを書きます。
- 02ベースモデルの種類、数、主要ハイパーパラメータを書きます。
- 03Stacking では、out-of-fold 予測の作成方法を書きます。
- 04欠測補完、標準化、カテゴリ変数処理を Pipeline として書きます。
- 05交差検証の分割方法、層化、施設単位分割の有無を書きます。
- 06AUC、Brier score、calibration、decision curve などを目的に応じて示します。
- 07線形モデル、正則化モデル、単一木などのベースラインと比較します。
査読では、複雑なモデルを使う理由が問われます。「アンサンブルだから高性能」ではなく、臨床課題に対して必要だった理由を説明します。FIM と年齢の単純な関係だけならロジスティック回帰で十分な場合もあり、施設差・認知機能・歩行指標・併存疾患の交互作用が強い場合に、木系アンサンブルの比較に意味が出てきます。
もう 1 つの論点は、解釈性です。アンサンブルは性能が上がる一方、臨床的に説明しにくくなることがあります。予測モデルとしての性能と、予後因子を検討する目的を分けて書きます。特徴量重要度を示す場合も、因果効果と混同しない表現にします。
// 09 · CHECKLIST実装前チェックリスト
- 01まず線形・ロジ・正則化モデルをベースラインにしましたか。
- 02Bagging、Boosting、Stacking の目的を分けて説明できますか。
- 03症例数に対して、モデル数やハイパーパラメータが多すぎませんか。
- 04前処理を Pipeline 内に入れていますか。
- 05Stacking のメタ特徴量を out-of-fold 予測で作っていますか。
- 06施設差がある場合、GroupKFold や外部検証を検討しましたか。
- 07AUC だけでなく calibration や Brier score を確認しましたか。
- 08特徴量重要度を因果効果として書いていませんか。
// 10 · QUIZ理解度チェック
-
Q1Bagging の主な目的として最も近いものはどれですか。
- 線形係数を推定する
- 分散の大きいモデルを安定させる
- 画像の畳み込みを行う
- 目的変数を削除する
SHOW ANSWER
B. 深い木のような不安定なモデルを平均して安定させます。 -
Q2Boosting の説明として適切なのはどれですか。
- 複数モデルを完全に独立に並列学習する
- 前のモデルの誤りや残差を次のモデルが補う
- カテゴリ変数だけを扱う
- 交差検証を不要にする
SHOW ANSWER
B. Boosting は順次学習が基本です。 -
Q3Stacking で特に重要な点はどれですか。
- 全データで学習した予測をメタモデルに渡す
- out-of-fold 予測をメタ特徴量として使う
- 欠測補完を分割前に全データで行う
- 評価指標は Accuracy だけでよい
SHOW ANSWER
B. 訓練データへの予測をそのまま使うと楽観評価になります。 -
Q4医療データでアンサンブルを使う際の注意点はどれですか。
- 複雑なモデルほど説明しやすい
- AUC が高ければ calibration は不要
- 症例数、CV 設計、解釈性を確認する
- ベースライン比較は不要
SHOW ANSWER
C. 性能だけでなく、汎化性能と説明可能性を確認します。
// 11 · FAQよくある質問
- Bagging と Boosting はどう使い分けますか?
- Bagging は深い決定木のように分散の大きいモデルを平均して安定させる方法です。Boosting は浅い木のようにバイアスが残るモデルを順に補正していく方法で、表形式データの予後予測でよく選ばれます。
- Stacking で気をつけることは?
- メタモデルに渡す予測は out-of-fold で作る必要があります。学習データへの予測をそのまま渡すと、評価が楽観的になります。小標本ではメタモデルまで含めて過学習しやすいため、線形モデルや単一木のベースライン比較が欠かせません。
- アンサンブルなら単一モデルより必ず良いですか?
- いいえ。小データでは複雑に組み合わせるほど過学習しやすくなります。性能だけでなく Calibration や Brier score、解釈性、CV 設計を含めて、線形・正則化モデルとの比較で判断します。
// REF参考文献
- Breiman L. Bagging predictors. Machine Learning 1996;24(2):123-140.
- Freund Y, Schapire RE. A decision-theoretic generalization of on-line learning and an application to boosting. Journal of Computer and System Sciences 1997;55(1):119-139.
- Wolpert DH. Stacked generalization. Neural Networks 1992;5(2):241-259.
- Dietterich TG. Ensemble methods in machine learning. Multiple Classifier Systems 2000;1857:1-15.
- Hastie T, Tibshirani R, Friedman J. The Elements of Statistical Learning. 2nd ed. Springer, 2009.
- Collins GS, Moons KGM, Dhiman P, et al. TRIPOD+AI statement: updated guidance for reporting clinical prediction models that use regression or machine learning methods. BMJ 2024;385:e078378.
- Moons KGM, Wolff RF, Riley RD, et al. PROBAST+AI: an updated quality, risk of bias, and applicability assessment tool for prediction models using regression or artificial intelligence methods. BMJ 2025;388:e082505.