// PART 02 · ARTICLE 02 / 07
DATA-PREP MISSING-DATA L2

欠損値処理(MCAR / MAR / MNAR・多重代入)

— 「欠測の型」を見極めて、適切に補完する

11 min read· L2· 2026.05.20 update· by Editor

臨床データでは、欠測は例外ではありません。 FIM、SIAS、握力、認知機能検査、追跡転帰は、 病状、施設、時期、評価者の影響を受けます。 欠測値処理では、単に空欄を埋めるだけでなく、 なぜ欠けたのかを考える必要があります。 その判断が、予測モデルの性能と解釈を左右します。

// CONTEXT

この記事では、MCAR / MAR / MNAR の違いを整理します。 そのうえで、列削除、complete-case、単純補完、 多重代入(MICE)、機械学習による補完を比較します。 補完器を全データで fit しないことも重視します。 関連する基本用語は 02·01 説明変数と目的変数と、 09·02 データリーケージとは何かも参照してください。

// 01 · LEARN OUTCOMESこの記事でわかること

  • MCAR / MAR / MNAR の違いを、臨床データで説明できます。
  • complete-case、単純補完、多重代入の限界を整理できます。
  • missing indicator を使う場面を判断できます。
  • 補完を Pipeline 内で fit する理由を説明できます。

// 02 · CONCLUSION最初に結論

// 03 · FIGURE欠測の型と補完の考え方

// MISSING DATA MECHANISMS MCAR MAR MNAR 完全にランダム 観測済み変数で説明可能 未観測量に依存 P(R | X, Y) = P(R) 例: 評価表が偶然紛失 例: 機器故障で1日記録なし 仮定強め · 実例少なめ complete-case でも 偏りは小さめ → 単純補完で十分 なことが多い P(R | X, Y) = P(R | X_obs) 例: 重症ほど SIAS 欠測 例: 高齢で認知検査未実施 臨床で最もよくある型 complete-case では 軽症側に偏る → MICE が選択肢 観測変数で補完 P(R | X, Y) ≠ P(R | X_obs) 例: 転帰不良ほど追跡不能 例: 状態悪化で評価不能 仮定に依存 · 注意 補完だけでは 偏りが残る場合あり → 感度分析が必須 Limitations に明記 R: 欠測インジケータ (観測=1 / 欠測=0) · X_obs: 観測済み説明変数 · Y: 目的変数
図1: MCAR / MAR / MNAR の概念図。MCAR は欠測が観測変数やアウトカムと独立、MAR は観測済み変数で説明可能、MNAR は未観測量やアウトカム自体に依存する状態として描く。

MCAR は、評価表が偶然紛失したような状態です。 欠測が患者背景にも転帰にも関係しない場合です。 しかし、臨床データではこの仮定は強めです。 欠測には理由があることが多いからです。

MAR は、欠測が観測済み変数で説明できる状態です。 たとえば、重症例ほど SIAS が未評価になりやすい場合です。 重症度、年齢、入院時 FIM などが記録されていれば、 それらを補完モデルに入れる余地があります。

MNAR は、欠測の起こりやすさが未観測量に依存します。 例として、転帰不良例ほど追跡不能になる状況があります。 この場合、観測済み変数だけでは説明しにくいです。 多重代入を用いても、仮定の影響が残ります。

// MEAN IMPUTATION vs MICE MEAN IMPUTATION 補完値が一点に集まる 年齢 FIM 平均値 MICE 複数の補完値で不確実性を残す 年齢 FIM 観測値 単一補完 MICE による複数補完
図2: 単純補完 vs MICE。平均補完は同じ値に集まり、分散を小さく見せる。MICE は複数の補完候補を作り、不確実性を分析に反映する。

// 04 · CLINICALリハ研究で起きやすい欠測

// CASE 1 · SIAS 下肢項目の欠測

回復期病棟 N=300 の研究を考えます。 SIAS 下肢項目の欠測が 8% あります。 欠測は重症例に多い傾向です。 この場合、完全なランダム欠測とは考えにくいです。 年齢、入院時 FIM、NIHSS などで説明できるなら、 MAR 仮定のもとで MICE を検討できます。

// CASE 2 · 頭部外傷後 6 か月 FIM

N=150 の頭部外傷研究を想定します。 6 か月後 FIM の追跡欠測が 22% あります。 転帰不良例ほど連絡不能になりやすいなら、 MNAR の可能性があります。 このときは、補完値だけに依存せず、 complete-case 解析との比較を併記します。

// CASE 3 · 多施設データの握力

多施設データでは、施設によって測定機器が異なります。 ある施設では握力計がなく、測定値が欠けることがあります。 この欠測は、患者の状態だけでなく施設に関係します。 施設 ID を補完モデルの共変量に入れると、 欠測の構造をより反映しやすくなります。

// CASE 4 · 認知機能スコアの空欄

電子カルテから自動抽出したデータでは、 認知機能スコアが未入力のことがあります。 未入力は、評価不能、時間不足、実施対象外など、 複数の意味を持ちます。 補完値に加えて欠測フラグを作ると、 「欠けていること」自体を特徴量にできます。

// 05 · THEORY欠測の型を確率で見る

欠測を考えるときは、観測された値だけを見ません。 「どの値が欠けたか」を示す変数 R を考えます。 R は、観測済みなら 1、欠測なら 0 のように表せます。 X は説明変数、Y は目的変数です。

MCAR : P(R | X, Y) = P(R)
       欠測が完全にランダム

MAR  : P(R | X, Y) = P(R | X_obs)
       欠測が観測済み変数で説明可能

MNAR : P(R | X, Y) != P(R | X_obs)
       欠測がアウトカムまたは未観測量に依存

MCAR では、欠測した症例を除いても、 推定の偏りは比較的小さくなります。 ただし、症例数は減ります。 信頼区間は広くなりやすいです。

MAR では、complete-case だけにすると偏りが入ります。 たとえば、重症例で SIAS が欠けやすい場合です。 欠測例を落とすと、軽症例に寄ったデータになります。 このときは、観測済み変数を使った補完が候補になります。

MNAR では、観測済み情報だけでは不十分です。 追跡不能の理由が、転帰不良そのものに関係する場合です。 欠測の仮定を変えた感度分析が重要になります。 解析結果の頑健性を確認するためです。

MICE の基本発想

MICE は、欠測列を 1 つずつ目的変数にします。 他の列を説明変数として回帰モデルを作ります。 これを繰り返して、複数の補完データセットを作ります。 最後に、各データセットの解析結果を統合します。

各欠測列について:
  1. 暫定値で初期化
  2. その列を目的とした回帰モデルを当てはめる
  3. 予測値で欠測を更新
  4. ループして M セットの補完データを得る
  5. 各データセットで分析
  6. Rubin's rules で統合

重要なのは、不確実性を残すことです。 欠測値を 1 つの値に固定すると、 データが本来よりそろって見えます。 その結果、分散や信頼区間が小さく見えることがあります。 多重代入は、この問題を軽減するための枠組みです [1][2]

// 06 · IMPLEMENTATIONPipeline で補完する実装例

実装で最も避けたいのは、全データで補完器を fit する流れです。 補完器は、中央値、分布、近傍情報を学習します。 test や validation の値が入ると、評価が楽観的になります。 scikit-learn では Pipeline に入れると、 CV の各 fold 内で fit されます。

# 教育用の仮想データを想定した例です。
# 実データで実行する前に、個人情報保護、倫理審査、
# 施設ルール、共同研究契約、利用規約を確認してください。
# 予測時点で取得できない列は、説明変数から外します。

import numpy as np
import pandas as pd

from sklearn.experimental import enable_iterative_imputer  # noqa: F401
from sklearn.impute import SimpleImputer, KNNImputer, IterativeImputer
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import (
    train_test_split,
    StratifiedKFold,
    GroupKFold,
    cross_validate,
)
from sklearn.metrics import roc_auc_score

RANDOM_STATE = 42

# 1. 読み込み
df = pd.read_csv("example_rehab_dataset.csv")

# 2. 欠測率の確認
missing_rate = (
    df.isna()
      .mean()
      .sort_values(ascending=False)
      .rename("missing_rate")
)
print(missing_rate.head(20))

# 3. 予測時点を確認して列を決める
# 例: 入院時点で退院時歩行自立を予測する想定です。
target = "walk_independent_discharge"
group_col = "patient_id"

numeric_features = [
    "age",
    "days_from_onset",
    "fim_motor_admission",
    "fim_cognition_admission",
    "sias_lower_admission",
    "grip_strength_admission",
]

categorical_features = [
    "sex",
    "stroke_type",
    "facility_id",
]

X = df[numeric_features + categorical_features].copy()
y = df[target].astype(int)
groups = df[group_col] if group_col in df.columns else None

# 4. 単純補完の比較用パイプライン
numeric_simple = Pipeline(
    steps=[
        ("imputer", SimpleImputer(strategy="median", add_indicator=True)),
        ("scaler", StandardScaler()),
    ]
)

categorical_simple = Pipeline(
    steps=[
        ("imputer", SimpleImputer(strategy="most_frequent")),
        ("onehot", OneHotEncoder(handle_unknown="ignore")),
    ]
)

preprocess_simple = ColumnTransformer(
    transformers=[
        ("num", numeric_simple, numeric_features),
        ("cat", categorical_simple, categorical_features),
    ]
)

pipe_simple = Pipeline(
    steps=[
        ("preprocess", preprocess_simple),
        (
            "model",
            LogisticRegression(max_iter=2000, class_weight="balanced"),
        ),
    ]
)

# 5. MICE 風の IterativeImputer
numeric_mice_like = Pipeline(
    steps=[
        (
            "imputer",
            IterativeImputer(
                random_state=RANDOM_STATE,
                max_iter=20,
                sample_posterior=True,
                add_indicator=True,
            ),
        ),
        ("scaler", StandardScaler()),
    ]
)

preprocess_mice_like = ColumnTransformer(
    transformers=[
        ("num", numeric_mice_like, numeric_features),
        ("cat", categorical_simple, categorical_features),
    ]
)

pipe_mice_like = Pipeline(
    steps=[
        ("preprocess", preprocess_mice_like),
        (
            "model",
            LogisticRegression(max_iter=2000, class_weight="balanced"),
        ),
    ]
)

# 6. KNNImputer の小例
numeric_knn = Pipeline(
    steps=[
        ("imputer", KNNImputer(n_neighbors=5, weights="distance")),
        ("scaler", StandardScaler()),
    ]
)

preprocess_knn = ColumnTransformer(
    transformers=[
        ("num", numeric_knn, numeric_features),
        ("cat", categorical_simple, categorical_features),
    ]
)

pipe_knn = Pipeline(
    steps=[
        ("preprocess", preprocess_knn),
        (
            "model",
            LogisticRegression(max_iter=2000, class_weight="balanced"),
        ),
    ]
)

# 7. train/test 分割後に fit する例
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    stratify=y,
    random_state=RANDOM_STATE,
)

pipe_mice_like.fit(X_train, y_train)
proba = pipe_mice_like.predict_proba(X_test)[:, 1]
print("test_auc", roc_auc_score(y_test, proba))

# 8. CV では fold 内で前処理が fit されます。
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=RANDOM_STATE)
cv_result = cross_validate(
    pipe_mice_like,
    X,
    y,
    cv=cv,
    scoring=["roc_auc", "accuracy"],
    return_train_score=False,
)
print(pd.DataFrame(cv_result).mean())

# 9. 同一患者の反復評価がある場合は GroupKFold も検討します。
if groups is not None and groups.nunique() >= 5:
    gcv = GroupKFold(n_splits=5)
    group_result = cross_validate(
        pipe_simple,
        X,
        y,
        cv=gcv,
        groups=groups,
        scoring="roc_auc",
    )
    print("group_auc", group_result["test_score"].mean())

# 10. NG 例: 全データで先に fit しない
# bad_imputer = SimpleImputer(strategy="median")
# X_bad = bad_imputer.fit_transform(X[numeric_features])
# X_train, X_test, y_train, y_test = train_test_split(X_bad, y)
# 上の流れでは test 側の分布も補完器に入ります。

この例では、数値列とカテゴリ列を分けています。 数値列は補完後に標準化します。 カテゴリ列は最頻値で補完し、One-Hot Encoding を行います。 どの処理も ColumnTransformer 内に置いています。

IterativeImputer は MICE 風の補完です。 ただし、古典的な多重代入と同一ではありません。 複数回の補完データを作り、結果を統合する設計が必要です。 実際の論文では、使用した回数、乱数、統合方法を記載します。

KNNImputer は近い症例から値を推定します。 直感的ですが、スケールや外れ値の影響を受けます。 高次元では距離が不安定になることもあります。 そのため、補完方法の選択は性能だけで決めません。 欠測の理由と臨床的妥当性も確認します。

// 07 · MYTHSよくある誤解

誤解: 欠測は全部削除すれば安全です。
complete-case は単純で説明しやすい方法です。 しかし、MAR や MNAR では偏りが入ります。 重症例が落ちると、モデルは軽症例中心に学習します。
誤解: 平均値補完をすれば問題ありません。
平均値補完は、欠測値を同じ値に集めます。 分散を小さく見せます。 p 値や信頼区間が過小評価されることがあります。
誤解: MICE を使えば欠測の問題は消えます。
MICE は補完モデルの仮定に依存します。 MAR に近い状況では有用です。 MNAR の偏りを単独で扱い切れない場合があります。
誤解: 欠測フラグを足せば十分です。
欠測フラグは有用な特徴量になることがあります。 一方で、欠測の因果構造は説明しません。 補完値、欠測理由、感度分析を組み合わせます。

// 08 · WRITING論文 Methods で書くこと

欠損値処理は、Methods の短い一文で済ませると、 査読で指摘されやすい部分です。 特に予測モデル研究では、補完と評価分割の順序が重要です。 TRIPOD+AI でも、データ処理の透明性が重視されています [6]

  • 各変数の欠測率を、表または補足表で示します。
  • 欠測の型について、MCAR / MAR / MNAR の観点で説明します。
  • 除外した列や症例がある場合、基準を明記します。
  • 補完方法、補完に使った変数、補完回数を記載します。
  • 補完器を train fold 内で fit したことを明記します。
  • complete-case 解析などの感度分析を示します。
  • 目的変数を補完モデルに入れたかを記載します。

目的変数を MICE の共変量に入れるかは、 研究目的によって扱いが変わります。 予測モデル開発では、評価データの目的変数情報が 前処理に混ざるとリーケージになります。 一方、説明目的の統計解析では、効率を上げるために 目的変数を含める設計もあります。 どちらの場合も、解析計画に明記します。

査読者が見たいのは、補完方法の名前だけではありません。 欠測がどのように発生したかという臨床的説明です。 たとえば、SIAS の欠測が重症度に関係するなら、 その仮定を Methods と Limitations に書きます。

// 09 · CHECKLIST欠測値処理チェックリスト

  • 01各列の欠測率を確認しましたか。
  • 02欠測の理由を、臨床・施設・時点から考えましたか。
  • 03MCAR / MAR / MNAR の仮定を記載できますか。
  • 04complete-case の偏りを確認しましたか。
  • 05平均値補完だけに依存していませんか。
  • 06補完器を Pipeline 内に入れましたか。
  • 07test / validation で補完器を fit していませんか。
  • 08感度分析を計画しましたか。

// 10 · QUIZ確認クイズ

  1. Q1重症例ほど SIAS が欠測しやすい場合、最も近い考え方はどれですか。
    • MCAR
    • MAR の可能性
    • 欠測ではない
    • 標準化の問題
    SHOW ANSWER
    B. 観測済みの重症度や FIM で説明できるなら、MAR として扱える可能性があります。
  2. Q2平均値補完の主な弱点はどれですか。
    • すべての外れ値を増やす
    • 分散を小さく見せやすい
    • カテゴリ変数だけに使える
    • CV が使えなくなる
    SHOW ANSWER
    B. 同じ平均値に集めるため、ばらつきが小さく見えることがあります。
  3. Q3予測モデルの評価で避けたい実装はどれですか。
    • Pipeline 内で補完する
    • fold 内で imputer を fit する
    • 全データで imputer を fit してから分割する
    • 欠測率を表に示す
    SHOW ANSWER
    C. test 側の分布が補完器に混ざるため、リーケージになります。
  4. Q4MNAR が疑われるときに重要な対応はどれですか。
    • 補完後の結果だけを示す
    • 欠測理由と感度分析を示す
    • すべて平均値で埋める
    • 目的変数を削除する
    SHOW ANSWER
    B. MNAR では仮定に依存するため、感度分析が重要になります。

// REF参考文献

  1. Rubin DB. Inference and missing data. Biometrika 1976;63(3):581-592.
  2. Little RJA, Rubin DB. Statistical Analysis with Missing Data. 3rd ed. Wiley; 2019.
  3. van Buuren S. Flexible Imputation of Missing Data. 2nd ed. CRC Press; 2018.
  4. Sterne JAC, White IR, Carlin JB, et al. Multiple imputation for missing data in epidemiological and clinical research: potential and pitfalls. BMJ 2009;338:b2393.
  5. Azur MJ, Stuart EA, Frangakis C, Leaf PJ. Multiple imputation by chained equations: what is it and how does it work? International Journal of Methods in Psychiatric Research 2011;20(1):40-49.
  6. Collins GS, Moons KGM, Dhiman P, et al. TRIPOD+AI statement. BMJ 2024;385:e078378.