ふくふくHukuhuku Inc.
EP.02Prep 9分公開: 2026-05-10

欠損値の扱い:削除・補完・フラグ化のトレードオフ

「平均値で補完」は最も安易で、最もバイアスを持ち込みやすい選択。MCAR/MAR/MNAR の分類、削除・補完・フラグ化の使い分け。

#欠損値#Imputation
CO📔 Google Colab で開く(上から順にセルを実行)
シェア

「とりあえず平均値で埋めとく」が分析を歪める典型例。欠損には性質の違いがあり、それに応じた処理を選ぶ必要があります。本記事では MCAR / MAR / MNAR の分類と、削除・補完・フラグ化の使い分けを共有します。

欠損の 3 種類

分類意味対処
MCAR(完全ランダム)欠損が完全にランダム通信エラーで一部記録ロス削除 OK、平均補完 OK
MAR(条件付きランダム)他の観測値で欠損が説明可能高齢者ほど ID なし回帰補完 / MICE
MNAR(非ランダム)欠損自体に意味がある高所得者ほど年収を答えないフラグ化推奨、削除/補完は危険

対処法の比較

  • Listwise deletion:欠損行を削除。サンプル数激減のリスク
  • Pairwise deletion:使う列のみで欠損行を除外。集計のたびに N が変わる
  • 平均 / 中央値補完:簡単だが分散が縮む、相関が歪む
  • 回帰補完:他の列から予測、ただし元の関係を強化してしまう
  • MICE(Multiple Imputation):複数の補完値を生成し、不確実性を保つ
  • 欠損フラグ追加:「欠損していた」というシグナル自体を学習に使う ── では強力

Python での実装

1. 欠損率と欠損パターンの可視化
Python
import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsimport japanize_matplotlib  # noqa: F401
# 欠損率を確認print(df.isna().mean().sort_values(ascending=False))
# 欠損パターンのヒートマップ(行=サンプル、列=特徴量、色=欠損)fig, ax = plt.subplots(figsize=(10, 6))sns.heatmap(df.isna(), cbar=False, yticklabels=False, cmap="Greys", ax=ax)ax.set_title("欠損パターン(黒=欠損)"); plt.tight_layout(); plt.show()
# 列同士の欠損相関(一緒に欠損するか)missing_corr = df.isna().corr()print(missing_corr.round(2))
2. 5 種類の補完手法を比較
Python
from sklearn.impute import SimpleImputer, KNNImputerfrom sklearn.experimental import enable_iterative_imputer  # noqafrom sklearn.impute import IterativeImputer
# 各手法を辞書でimputers = {    "削除": lambda d: d.dropna(),    "平均補完": lambda d: d.fillna(d.mean(numeric_only=True)),    "中央値補完": lambda d: d.fillna(d.median(numeric_only=True)),    "KNN(k=5)": lambda d: pd.DataFrame(        KNNImputer(n_neighbors=5).fit_transform(d.select_dtypes("number")),        columns=d.select_dtypes("number").columns,        index=d.index,    ),    "MICE": lambda d: pd.DataFrame(        IterativeImputer(max_iter=10, random_state=42).fit_transform(d.select_dtypes("number")),        columns=d.select_dtypes("number").columns,        index=d.index,    ),}
results = {}for name, fn in imputers.items():    imputed = fn(df.copy())    if "income" in imputed.columns:        results[name] = {            "n": len(imputed),            "mean": imputed["income"].mean(),            "std": imputed["income"].std(),        }print(pd.DataFrame(results).T.round(0))
3. 「欠損フラグ列」を追加(ML で強力)
Python
# 補完前にフラグ列を作る(これが最重要)def add_missing_flags(df: pd.DataFrame, cols: list[str]) -> pd.DataFrame:    for col in cols:        df[f"{col}_was_missing"] = df[col].isna().astype(int)    return df
# 1. フラグ追加df = add_missing_flags(df, ["age", "income", "tenure"])
# 2. その後で補完df = df.fillna(df.median(numeric_only=True))
# 3. ML モデルにはフラグ列も特徴量として渡す# → 「欠損していたユーザー」がモデル予測に使えるシグナルになる# 例:「年収未回答 = 高所得層」という相関を学習可能(MNAR 対応)
4. 列ごとに最適手法を自動選定
Python
def auto_impute(df: pd.DataFrame, target_col: str | None = None) -> pd.DataFrame:    """欠損率と型に応じて自動で手法を選ぶ"""    df = df.copy()    for col in df.columns:        missing_pct = df[col].isna().mean()
        if missing_pct == 0:            continue        if missing_pct > 0.5:            print(f"[skip] {col}: 欠損 {missing_pct:.0%} → 列削除を検討")            df = df.drop(columns=[col])            continue
        # フラグ追加        df[f"{col}_was_missing"] = df[col].isna().astype(int)
        if df[col].dtype.kind in "ifu":  # 数値            if missing_pct < 0.05:                df[col] = df[col].fillna(df[col].median())            else:                # 5% 以上は KNN                from sklearn.impute import KNNImputer                num_cols = df.select_dtypes("number").columns                df[num_cols] = KNNImputer(n_neighbors=5).fit_transform(df[num_cols])                break        else:  # カテゴリ            df[col] = df[col].fillna(df[col].mode()[0])    return df
cleaned = auto_impute(df)

ふくふくの進め方

欠損だらけで困っている」というご相談には、欠損パターンの分析(1 週間)→ 列ごとの処理選定 → パイプライン化を 1〜2 週間で。MNAR を見落とすと分析が壊れるので、最初の診断が最重要です。

次回予告

EP.03 は外れ値の検出と除去。「3σ から外れたら除去」が破綻する話と、IQR / MAD / Winsorize の使い分け。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp