医療AIモデルは、開発施設では高性能でも、別施設では性能が下がることがあります。これは単に「モデルが弱い」だけではありません。患者背景・重症度・併存疾患・検査機器・撮影条件・評価者・入院期間・リハビリ提供量・退院支援の方針が変わると、モデルが入力として受け取るデータの分布も、アウトカムの意味も変わります。
学習時のデータ分布と、評価・実装時のデータ分布がずれることを、本稿では広く 施設差・ドメインシフト と呼びます。第9部のなかでも、これは実装に最も近い落とし穴です。過学習・データリーケージ・小規模データ・不均衡・欠測に注意しても、開発施設と運用施設が違えば、性能は簡単に揺らぎます。
本稿は、第9部「医療AI研究の落とし穴と対策」の第7記事です。09·02 データリーケージ・09·05 多重比較・09·06 欠測バイアス とも関係します。リハビリ領域では、FIM・歩行自立・退院先・PUL・動画評価・画像特徴量などが施設差の影響を受けやすく、外部検証の設計が論文の説得力を大きく左右します。較正の前段は 14·04 DCA デモ、評価設計は 14·02 交差検証デモ も併せて参照すると立体的に理解できます。
// 01 · LEARN OUTCOMESこの記事で学ぶこと
- 施設差・ドメインシフトを、患者背景・測定・評価・診療プロセス・時間変化に分けて説明できる。
- ランダム分割の内部検証だけでは、未知施設での性能を十分に評価できない理由を理解する。
- covariate shift・label shift・concept drift・measurement shift・workflow shift・temporal drift を区別できる。
- GroupKFold・leave-one-site-out・時間順分割・外部検証の使い分けを整理できる。
- AUC だけでなく、Calibration・Decision Curve・サブグループ性能で性能低下を評価できる。
- 外部検証後の再較正・モデル更新・再学習・運用監視をどう設計するか説明できる。
// 02 · CONCLUSIONまず結論
// 03 · FIGUREドメインシフトを図で理解する
施設差は「別施設だから違う」とまとめると曖昧になります。研究計画では、何がずれているのかを分解しておくと、性能低下の原因を説明しやすくなります。まず全体像を確認します。
次に、内部検証の分割方法ごとに、何を一般化できているかを確認します。ランダム分割・GroupKFold(施設別 CV)・外部検証は、評価対象の患者集団が異なります。
最後に、外部検証で「AUC が高ければ大丈夫」と早合点しないために、較正ドリフトを視覚化します。順位付けは保たれても、確率の絶対値が施設間でずれることがあります。
// 04 · CLINICALリハ・神経・整形領域での具体例
回復期リハビリ病棟で退院時 FIM 合計点や歩行自立を予測する場合、施設差は非常に大きな問題になります。入院時 FIM が同じでも、入院までの日数・リハビリ単位数・退院支援体制・家族介護力・地域包括ケアの整備状況が異なれば、退院時アウトカムは変わります。退院時 FIM や自宅退院は「患者の機能」だけでなく、「施設の診療プロセスを含むアウトカム」です。施設 A のモデルを施設 B で使う際は、AUC だけでなく予測確率が過大・過小になっていないかを Calibration plot で確認します。
Duchenne 型筋ジストロフィーの上肢機能を動画から評価する場合、撮影角度・カメラ位置・照明・椅子と机の高さ・課題指示・PUL 評価者の採点傾向が変わると、骨格時系列の分布もラベルの意味もずれます。モデルが代償運動を見ているつもりで、実は 施設固有の撮影環境 を学習している可能性があります。症例数が少なくても、撮影条件の標準化・評価者間一致・施設 ID と撮影条件の記録・leave-one-subject-out / session-wise split の設計が必要です。
画像 AI では、機器差とプロトコル差が大きなドメインシフトです。CT のスライス厚・再構成カーネル・DICOM タグ、MRI のメーカー・磁場強度・シーケンス・前処理方法が変わると、病変そのものではなく画像の質感やノイズを学習することがあります。外部検証に加えて、機器別・プロトコル別のサブグループ解析、画像前処理の標準化、DICOM 由来情報への依存確認、「施設識別器が施設を当てられるか」の点検が有用です。
SMA や DMD のような希少疾患では、施設ごとの症例数が限られます。単一施設モデルは過学習だけでなく、施設固有の診療方針や評価時期に強く依存します。疾患修飾薬の導入時期・フォロー間隔・機能評価の実施頻度が変わると、過去データで作ったモデルが現在の患者に合わなくなります。施設・時期をまたいだ GroupKFold と、疾患修飾薬導入前後での時間順分割を併用することで、temporal drift の影響を可視化できます。
// 05 · THEORYドメインシフトの分類と検証の意味
シフトの 6 タイプ
施設差を整理するには、どの分布が変わったのかを分けて考えます。P(X)(入力分布)、P(Y)(アウトカム分布)、P(Y|X)(入力とアウトカムの関係)のどれがずれているかで、対策も変わります[5]。
| シフトの型 | 変化する分布 | 医療・リハの例 |
|---|---|---|
| Covariate shift | P(X) | B 施設は高齢者が多い/CT 撮影条件・動画の角度が違う |
| Label shift | P(Y) | 歩行自立率・自宅退院率・死亡率・再入院率が施設や時期で異なる |
| Concept drift | P(Y|X) | 治療法・リハ提供量・退院基準・疾患修飾薬で、同じ入力でも予後が変わる |
| Measurement shift | P(X) のうち測定由来 | FIM 採点者・PUL 評価者・CT/MRI 機器・スライス厚・センサー装着位置 |
| Workflow shift | P(X), P(Y) 同時 | 入院適応・転院時期・リハ単位数・退院支援・外来フォローの有無 |
| Temporal drift | すべて経時的に | 新薬・診療報酬改定・COVID-19・スタッフ交代 |
ランダム分割の何が楽観的か
単一施設データをランダムに train/test へ分けると、train にも test にも同じ施設の患者が入ります。この評価は「同じ施設の同じ運用環境で、似た患者が来たときの性能」に近いものです。未知施設への汎化性能は、これだけでは評価できません。
| 検証方法 | 何を評価しているか | 注意点 |
|---|---|---|
| ランダム分割 | 同じ施設・似た運用内での性能 | 施設固有の癖を共有し楽観的 |
| k-fold CV | 同一母集団内での平均的汎化 | 患者・施設・評価者の独立性を壊さない設計が必要 |
| GroupKFold | 患者 ID・施設 ID・評価者 ID をまたいだ汎化 | group 数が少ないと推定が不安定 |
| leave-one-site-out | 未知施設に持ち込んだ性能 | 施設数が少ないと結果が施設依存 |
| 時間順分割 | 将来の患者に対する性能 | 治療変化・記録方法の変化を受ける |
| 完全外部検証 | 独立施設・独立期間での性能 | 開発で一切使わない「封筒」として扱う |
較正の評価:discrimination だけでは足りない
外部検証で最低限確認したいのは次の 4 つです。①discrimination:AUC や C-index、②calibration:Calibration plot・calibration-in-the-large・calibration slope、③threshold-based performance:臨床閾値ごとの感度・特異度・PPV・NPV、④clinical utility:Decision Curve Analysis。AUC で順位付けが保たれていても、確率の絶対値がずれていれば臨床判断には使えません。
Calibration の基本量
calibration-in-the-large : 観測平均 − 予測平均
≈ 0 が望ましい
calibration slope : logit(p̂) を logit(p) で回帰した傾き
1.0 が望ましい
< 1.0 → 過信気味 (over-confident)
> 1.0 → 控えめ気味 (under-confident)
Brier score : Σ (p̂ − y)² / N
離散性・較正・順位の総合指標
// 06 · IMPLEMENTATION実装:GroupKFold・時間順分割・再較正
解析ではまず「何を一般化したいのか」を決めます。同じ施設の将来患者に使いたいのか、別施設に持ち込みたいのか、全国レジストリで広く使いたいのかで、分割方法が変わります。
# ============================================================
# 施設 ID を group にした GroupKFold
# 同じ施設の症例が train/test にまたがらない
# ============================================================
import numpy as np
import pandas as pd
from sklearn.model_selection import GroupKFold, cross_validate
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.linear_model import LogisticRegression
X = df[predictor_cols]
y = df["outcome"]
groups = df["facility_id"]
preprocess = ColumnTransformer([
("num", Pipeline([("imp", SimpleImputer(strategy="median")),
("scl", StandardScaler())]), numeric_cols),
("cat", Pipeline([("imp", SimpleImputer(strategy="most_frequent")),
("ohe", OneHotEncoder(handle_unknown="ignore"))]), categorical_cols),
])
model = Pipeline([
("prep", preprocess),
("clf", LogisticRegression(max_iter=2000, class_weight="balanced")),
])
cv = GroupKFold(n_splits=5)
result = cross_validate(
model, X, y, groups=groups, cv=cv,
scoring=["roc_auc", "neg_brier_score", "average_precision"],
return_estimator=True,
)
print(f"AUC: {result['test_roc_auc'].mean():.3f} ± {result['test_roc_auc'].std():.3f}")
# ============================================================
# 時間順分割 (temporal split)
# 過去で学習、未来で評価。時間的変化に対する脆弱性を可視化
# ============================================================
train = df[df["admission_date"] < "2024-01-01"]
test = df[df["admission_date"] >= "2024-01-01"]
model.fit(train[predictor_cols], train["outcome"])
proba = model.predict_proba(test[predictor_cols])[:, 1]
from sklearn.metrics import (roc_auc_score, brier_score_loss,
average_precision_score)
print(f"ROC-AUC : {roc_auc_score(test['outcome'], proba):.3f}")
print(f"PR-AUC : {average_precision_score(test['outcome'], proba):.3f}")
print(f"Brier : {brier_score_loss(test['outcome'], proba):.3f}")
# ============================================================
# 外部検証後の Calibration 評価 + Platt-scaling 再較正
# 注意: 再較正に使ったデータと評価データは分ける
# ============================================================
from sklearn.linear_model import LogisticRegression
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt
p = np.clip(model.predict_proba(X_ext_recal)[:, 1], 1e-6, 1 - 1e-6)
logit_p = np.log(p / (1 - p)).reshape(-1, 1)
# Platt-scaling: ロジット → 観測結果へ単回帰
recalibrator = LogisticRegression()
recalibrator.fit(logit_p, y_ext_recal)
# 評価は別データで
p_eval = np.clip(model.predict_proba(X_ext_eval)[:, 1], 1e-6, 1 - 1e-6)
logit_eval = np.log(p_eval / (1 - p_eval)).reshape(-1, 1)
p_recal = recalibrator.predict_proba(logit_eval)[:, 1]
# Calibration curve
prob_true_raw, prob_pred_raw = calibration_curve(y_ext_eval, p_eval, n_bins=10)
prob_true_recal, prob_pred_recal = calibration_curve(y_ext_eval, p_recal, n_bins=10)
# calibration intercept / slope
def cal_intercept_slope(y, p):
z = np.log(np.clip(p, 1e-6, 1-1e-6) / (1 - np.clip(p, 1e-6, 1-1e-6)))
lr = LogisticRegression().fit(z.reshape(-1, 1), y)
return lr.intercept_[0], lr.coef_[0, 0]
i_raw, s_raw = cal_intercept_slope(y_ext_eval, p_eval)
i_recal, s_recal = cal_intercept_slope(y_ext_eval, p_recal)
print(f"raw : intercept={i_raw:.2f}, slope={s_raw:.2f}")
print(f"recal : intercept={i_recal:.2f}, slope={s_recal:.2f}")
再較正に使ったデータで再評価しない。 同じ外部データを「再較正」と「評価」の両方に使うと、再較正後の数字が楽観的に出ます。外部検証データを最初から「再較正用」と「評価用」に分けるか、再較正後の評価には別の独立データを用意します。それも難しい場合は、Discussion の Limitations に明記します。
再較正・モデル更新の階段
外部施設で性能が落ちたとき、選択肢は段階的にあります[4]。
Level 1 : Re-calibration (intercept のみ調整)
→ calibration-in-the-large の補正
Level 2 : Re-calibration (intercept + slope)
→ Platt-scaling / logistic recalibration
Level 3 : Model revision (係数の再推定)
→ 構造は維持しつつ施設固有データで refit
Level 4 : Model extension (新変数の追加)
→ 施設特有の予測子を組み込む
Level 5 : Full re-development
→ 新しいモデルを開発し直す
低レベルほどデータ要求が小さく、解釈も容易。
レベルが上がるほど、評価には新たな独立データが必要。
// 07 · MYTHS誤解と訂正
「内部検証で AUC が高ければ、外部施設でも同じ性能が出る」
順位付け性能は比較的保たれることもありますが、Calibration は崩れやすい指標です。外部検証では AUC ・ Calibration ・ 閾値別性能 ・ DCA を併せて評価します。AUC だけを根拠に臨床応用を主張すると、確率を意思決定に使う場面で破綻します。
「単一施設の研究では外部検証は無理だから言及しなくてよい」
外部データが手元になくても、時間順分割・評価者 ID をまたいだ GroupKFold・撮影機器別サブグループ解析など、内部で擬似的にシフトを再現する方法はあります。Limitations に「外部検証は今後の計画」と明記することは最低限の責任です。
「再較正すれば外部施設での性能は完全に補正できる」
再較正は確率の絶対値を補正しますが、discrimination や concept drift(P(Y|X) の変化)は補正しません。施設間で予測子とアウトカムの関係そのものが変わっている場合は、モデル修正・拡張・再開発が必要です。
「外部検証データでモデルを更新したら、その同じデータで性能を報告できる」
更新に使ったデータは「未使用データ」ではなくなり、評価は楽観的に偏ります。理想は再較正用と評価用にデータを分けること。分けられない場合は、更新後の性能を「探索的・参考値」と明記し、別データでの検証を将来計画に含めます。
// 08 · WRITING医療AI論文での書き方と査読対応
Methods に書くこと
- 開発データと検証データの施設数・対象期間・選択基準・除外基準
- 施設 ID・評価者 ID・機器・撮影条件・評価時期・診療プロセスの記録方法
- ランダム分割/GroupKFold/時間順分割/外部検証のどれを使ったか
- 前処理・欠測補完・標準化・特徴量選択をどの fold 内で fit したか
- 外部検証時にモデルを固定したか、再較正したか、モデル更新したか
Results に書くこと
- 開発データと外部検証データの患者背景比較(Table 1)
- アウトカム発生率・欠測割合・主要変数の分布差
- AUC・Calibration slope/intercept・Brier score・DCA
- 施設別・時期別・年齢層別・重症度別のサブグループ性能
- 性能低下があった場合、その大きさと臨床的意味
Discussion に書くこと
- 性能低下を患者背景・測定条件・診療プロセス・アウトカム定義の差として考察する
- 外部検証がない場合は、実装可能性を慎重に述べる
- 単一施設研究の場合、一般化可能性の限界を明記する
- 再較正・モデル更新・前向き検証・運用監視の必要性を述べる
Methods 例:「外部検証では、開発に使用しなかった独立施設のデータに固定済みモデルを適用し、discrimination・calibration・clinical utility を評価した。前処理および欠測補完は開発データで fit し、外部検証データには変換のみを適用した。」
Discussion 例:「外部検証では AUC は大きく低下しなかった一方、予測確率は全体に過大推定であった (calibration intercept = −0.42, slope = 0.78)。これは、開発施設と検証施設におけるアウトカム発生率、退院支援体制、評価時期の違いを反映している可能性がある。」
査読でよく問われる点
| 査読コメント | 背景にある懸念 | 対策 |
|---|---|---|
| 単一施設研究で一般化可能性が不明 | 施設固有の診療プロセスを学習している可能性 | 限界明記・時間順分割・外部検証計画 |
| ランダム分割のみで外部検証がない | 未知施設での性能が評価されていない | GroupKFold・leave-one-site-out・独立検証 |
| 開発/検証データの背景差が示されていない | 性能低下の原因が解釈できない | Table 1 で背景比較 |
| Calibration が評価されていない | 予測確率を臨床判断に使えない | Calibration plot・slope/intercept・Brier |
| 施設別性能が示されていない | 一部施設で不公平な性能低下のリスク | 施設別・サブグループ別解析 |
外部検証なしの限界を Methods/Discussion で書く際は 13·04 論文の Methods を書くプロンプト、外部検証コメントへの査読返信は 13·03 査読コメントに返信するプロンプト を参照してください。
// 09 · CHECKLIST投稿前チェックリスト
解析開始時・投稿前の双方で確認したい項目です。特に外部検証の有無・施設別分割・Calibration の評価は、医療AI論文の説得力に直結します。
- 01開発データと検証データの施設・期間・対象基準を明記した
- 02施設 ID・時期・機器・評価者・撮影条件を記録した
- 03ランダム分割だけでなく、施設別または時間順の検証を検討した
- 04複数施設データでは、同一施設が train/test にまたがる影響を確認した
- 05開発データと外部検証データの患者背景を比較した(Table 1)
- 06外部検証では AUC だけでなく Calibration を評価した
- 07臨床閾値ごとの感度・特異度・PPV・NPV を確認した
- 08Decision Curve などで臨床的有用性を確認した
- 09施設別・時期別・重症度別のサブグループ性能を確認した
- 10性能低下の原因を患者背景・測定条件・診療プロセスに分けて考察した
- 11再較正やモデル更新を行った場合、評価データとの関係を明記した
- 12外部検証がない場合は、実装可能性を慎重に表現した
// 10 · QUIZミニクイズ
-
Q1施設 A で作った歩行自立予測モデルを施設 B に適用したところ、AUC は保たれたが予測確率が全体に高すぎました。最も疑うべき問題は?
- Calibration のずれ(較正ドリフト)
- AUC の計算ミスのみ
- 施設差は存在しない
- 欠測が完全になくなった
SHOW ANSWER
A. 順位付け性能が保たれていても、予測確率の絶対値はずれることがあります。外部検証では Calibration slope/intercept・Calibration plot・DCA を必ず確認します。 -
Q2未知施設への汎化性能を内部データで近似したい場合、有用な分割はどれですか?
- 完全ランダム分割のみ
- 施設 ID を group にした GroupKFold
- test データで標準化を fit する
- 高性能だった fold だけ報告する
SHOW ANSWER
B. GroupKFold や leave-one-site-out は、施設単位で未知データを作るため、ランダム分割より厳しい検証になります。 -
Q3CT 画像 AI が、病変ではなくスライス厚や再構成条件を手がかりに予測している可能性があります。これは何に近い問題ですか?
- 測定条件由来のドメインシフト、または次稿のショートカット学習
- 完全に望ましい特徴量
- 外部検証が不要である証拠
- 欠測補完の成功例
SHOW ANSWER
A. 機器や撮影条件が施設・アウトカムと結びつくと、病変ではなく施設差を拾います。次稿(09·08 ショートカット学習)にもつながる典型例です。 -
Q4外部検証データを使ってモデルを再較正した後、その同じデータで性能を報告しました。何が問題ですか?
- 再較正に使ったデータで評価すると楽観的になりやすい
- 再較正は常に禁止
- 外部検証は不要
- AUC が必ず 0.5 になる
SHOW ANSWER
A. 更新・再較正に使ったデータは、もはや完全な未使用データではありません。更新後モデルの評価には別の独立データが望ましいです。
// 11 · FAQよくある質問
- 単一施設データだけでも論文は書けますか?
- 書けますが、一般化可能性の限界を Limitations に明記する必要があります。少なくとも時間順分割や評価者 ID・撮影機器 ID をまたいだ GroupKFold で内部の頑健性を示し、外部検証は今後の計画として記載します。TRIPOD+AI と PROBAST+AI は、開発のみの研究と外部検証付き研究を区別して評価します。
- 外部検証で AUC が保たれていれば臨床応用してよいですか?
- AUC だけでは不十分です。順位付け性能が保たれていても、予測確率の絶対値が施設間でずれていることがあります(較正ドリフト)。Calibration plot・calibration slope/intercept・Decision Curve Analysis・閾値別の感度/特異度/PPV/NPV を併せて評価し、必要に応じて再較正やモデル更新を検討します。
- 再較正したら、同じデータで性能を再評価してよいですか?
- 避けるべきです。再較正に使ったデータは、もはや完全な未使用データではないため、同じデータで評価すると楽観的な数字が出ます。理想的には外部検証データを「再較正用」と「評価用」に分けるか、再較正後の評価には別の独立データを用います。
- 何施設あれば leave-one-site-out が意味を持ちますか?
- 厳密な閾値はありませんが、施設数が 5 未満では推定が施設依存になりやすく、結果の安定性が乏しくなります。可能なら 5〜10 施設以上、難しい場合は時間順分割や撮影機器別の擬似外部検証を併用して、複数視点で頑健性を示します。
// REF参考文献
- Collins GS, Moons KGM, Dhiman P, Riley RD, Beam AL, Van Calster B, et al. TRIPOD+AI statement: updated guidance for reporting clinical prediction models that use regression or machine learning methods. BMJ 2024;385:e078378. — doi
- 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. — doi
- Collins GS, Dhiman P, Andaur Navarro CL, et al. Evaluation of clinical prediction models (part 1): from development to external validation. BMJ 2024;384:e074819. — link
- Binuya MAE, Engelhardt EG, Schats W, Schmidt MK, Steyerberg EW. Methodological guidance for the evaluation and updating of clinical prediction models: a systematic review. BMC Med Res Methodol 2022;22:316. — link
- dos Santos Silva GF, et al. Strategies for detecting and mitigating dataset shift in machine learning for health predictions: a systematic review. J Biomed Inform 2025. — link
- Subasri V, et al. Detecting and Remediating Harmful Data Shifts for Clinical Artificial Intelligence. JAMA Netw Open 2025. — link
- Guo X, et al. MedShift: Automated Identification of Shift Data for Medical Image Dataset Curation. IEEE J Biomed Health Inform 2023. — link