偽陽性(FP)は「本当は陰性なのに陽性と判定した件数」。仮説検定では第一種の過誤(α エラー)、医療検査では「偽陽性」、情報検索では誤検出と呼ばれる。FP を陰性全体(FP + TN)で割ると偽陽性率 FPR、1 − FPR が特異度になり、陽性と判定した件数(TP + FP)の中の割合として見ると適合率の裏返しになる。
🍰 まずはやさしく
偽陽性は、間違いで「あり」と出ることです。
判定のミスを正しく知るために使います。
大事なメールが迷惑メールに分類される例です。
まずは結論を短くまとめました。
最も忙しい読者のために、 まず結論だけまとめます。 詳細は以下のセクションへ:
🍰 まずはやさしく
偽陽性は、日常のいたるところにあります。
予測がどれくらい正しいか測るために使います。
スマホの検査キットなどで出会う考え方です。
この言葉がどこで使われるかを見ていきましょう。
「コロナの抗原検査の偽陽性率 5%」 「迷惑メールフィルタが大事なメールを消した」 — 全て偽陽性の問題。 二値分類の評価では必ず登場する基本概念。
🍰 まずはやさしく
偽陽性は、いわば「空振り」のようなものです。
ミスの種類によって困り方が違うことを知るためです。
火災報知器が、火事でないのに鳴る例です。
イメージで分かりやすく解説します。
偽陽性 (False Positive, FP) とは「本当は陰性なのに、 予測モデルや検査が陽性と判定した」事例のこと。 統計検定の Type I error (α) と概念的に対応します。 火災報知器で考えると整理が容易です。
| 予測 / 真実 | 火事 (陽性) | 火事でない (陰性) |
|---|---|---|
| 鳴る (陽性予測) | TP 火事 → 鳴る (正解) | FP 火事でない → 鳴る (誤報・住民迷惑) |
| 鳴らない (陰性予測) | FN 火事 → 鳴らない (致命的・人命) | TN 火事でない → 鳴らない (正解) |
火災報知器では FN > FP のコスト (人命 > 誤報)。 一方、 スパムフィルタでは FP (正規メールを spam フォルダに送る) のほうが深刻で、 大事なメールを見逃した瞬間にユーザーが離脱します。 医療検診でも、 PCR 検査は FP 多めでも構わない (偽陽性は再検査で訂正可) が、 確定診断では FP コストが急上昇 (患者に誤って癌告知)。 検査・予測のフェーズで FP コストが変動するのが特徴。
FP は 偽陰性 (FN) とトレードオフ関係にあり、 閾値を下げれば FN は減るが FP が増えます。 業務コストと有病率を踏まえて、 ROC 曲線 上の最適点を選ぶのが正攻法です。
空港の手荷物検査で「ピー」と鳴ったのに調べたら鍵束だった、 これが FP。 もし君が旅行者で、 急いでいるのに毎回 FP で止められたらどう感じるか? 逆に感度を下げれば FP は減るが、 本物の危険物(FN)を見逃すリスクが跳ね上がる。 だから探知機の閾値は「FP の不快コスト」と「FN の人命コスト」のバランスで決められている。
SSDSE-B-2026 の 47 都道府県を対象に「次年度に人口減少する県」を予測モデルでスクリーニングする例を考える。 真の人口減少県は 40 県(陽性 base rate ≈ 0.85)。 モデルが 43 県を「減少」と予測し、 内訳が TP=37・FP=6・FN=3・TN=1 だったとする。
| 指標 | 計算 | 値 | 意味 |
|---|---|---|---|
| FPR | 6 / (6+1) | 0.857 | 真の非減少県の 86% を誤検出 |
| 陽性適中率 | 37 / (37+6) | 0.860 | 予測陽性のうち 86% は本当に減少 |
| 感度 | 37 / (37+3) | 0.925 | 真の減少県の 93% を捕捉 |
「FP が多い」と即「悪いモデル」ではない。 有病率(base rate)が高いタスクでは FP の多さよりも FN を抑える方が重要なケースが多い。
🍰 まずはやさしく
偽陽性は、数式で計算できる間違いです。
ミスの割合を正確に求めるために使います。
検査の結果を、表にして整理する例です。
定義と計算方法について詳しく説明します。
有病率 1% の病気で精度 99% の検査を実施(100,000 人):
| 陽性 (検査) | 陰性 (検査) | 合計 | |
|---|---|---|---|
| 病気あり (1%) | 990 (TP) | 10 (FN) | 1,000 |
| 病気なし (99%) | 990 (FP) | 98,010 (TN) | 99,000 |
陽性判定された 1,980 人のうち、 実際に病気の人は 990 人(半分)。 残り半分は健康なのに陽性 = FP。 精度 99% でも有病率が低いと 陽性的中率は 50%!
SSDSE-B-2026 (2023 年・47 都道府県) の A1101 総人口を使い、 「人口 200 万人以上 = 陽性」を真のラベルとする。 一方、 予測モデルは A4101 出生数が 11,000 人以上なら陽性と予測した (出生数は人口とおおむね比例するため簡便な代理指標になる)。 このとき何件 FP が出るかを手計算する。
| 都道府県コード | A1101 総人口 (人) | 真 (人口 200 万以上) | A4101 出生数 (人) | 予測 (出生数 11,000 以上) | 判定 |
|---|---|---|---|---|---|
| R01000 北海道 | 5,092,000 | 陽性 | 24,430 | 陽性 | TP |
| R13000 東京 | 14,086,000 | 陽性 | 86,348 | 陽性 | TP |
| R15000 新潟 | 2,126,000 | 陽性 | 10,916 | 陰性 | FN |
| R47000 沖縄 | 1,468,000 | 陰性 | 12,549 | 陽性 | FP |
| R05000 秋田 | 914,000 | 陰性 | 3,611 | 陰性 | TN |
このコードでやること: SSDSE-B-2026 (2023 年 47 都道府県) で A1101 人口 ≧ 200 万 = 真陽性、 A4101 出生数 ≧ 11,000 = 予測陽性 として混同行列を計算する。 上記 Step 2 の手計算 (FPR=0.500 on 5 県) を含む 47 県全体で再現。
📥 入力: data/raw/SSDSE-B-2026.csv の A1101 (総人口、 単位: 人)、 A4101 (出生数、 単位: 人)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd from sklearn.metrics import confusion_matrix df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023] # 2023 年 47 都道府県 y_true = (d['A1101'] >= 2000000).astype(int) # 総人口 200 万人以上 = 真陽性 y_pred = (d['A4101'] >= 11000).astype(int) # 出生数 11,000 人以上 = 予測陽性 tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel() print(f'TP={tp}, FP={fp}, TN={tn}, FN={fn}') print(f'FPR = {fp/(fp+tn):.3f}, Precision = {tp/(tp+fp):.3f}') # 5 県抜粋で Step 2 と照合 small = d[d['Code'].isin(['R01000','R05000','R13000','R15000','R47000'])] yt = (small['A1101'] >= 2000000).astype(int) yp = (small['A4101'] >= 11000).astype(int) tn2, fp2, fn2, tp2 = confusion_matrix(yt, yp).ravel() print(f'5 県抜粋: FP={fp2}, TN={tn2}, FPR={fp2/(fp2+tn2):.3f}') |
📤 実行結果:
💬 5 県抜粋の FP=1 / FPR=0.500 は Step 2 の手計算と完全一致。 47 県全体では FP=3・FPR=0.097 (出生数は多いが人口 200 万未満の県が 3 件: 岡山・熊本・沖縄)。 出生数は人口と相関するが同一ではないため、 都市規模の割に出生数が多い県で FP が生じる。
偽陽性 (False Positive, FP) は「誤警報」の指標。 検査・スパムフィルタ・侵入検知のように、 陽性判定が下流コスト (精密検査・確認手間・通報対応) を発生させる場面で深刻になります。 FP 特有の罠 5 つ。
※ 上記は混同行列・ROC 解析・ベイズ統計の知見をもとに、 偽陽性が問題化する具体場面に沿って整理したもの。 ドメインの有病率・コスト比で重み付けを調整すること。
偽陽性 (FP) は単独の指標ではなく、 混同行列・閾値・多重比較・ベイズ更新と「家系図」のように繋がる。 SSDSE-B-2026 で「人口 200 万以上県」を識別するモデル (47 県、 陽性 16 / 陰性 31) を題材に整理する。
| 指標 | 定義 | SSDSE 47 県での値 | FP との関係 |
|---|---|---|---|
| FPR (偽陽性率) | FP / (FP+TN) | 3/31 ≒ 0.097 | 陰性のうち誤って陽性とした割合 (ROC の x 軸) |
| Precision (適合率) | TP / (TP+FP) | 15/18 ≒ 0.833 | 分母に FP が直接入る、 FP↑ で Precision↓ |
| Specificity (特異度) | TN / (TN+FP) = 1 - FPR | 28/31 ≒ 0.903 | 1 - FPR の関係、 医学検査で頻出 |
| FDR | FP / (FP+TP) | 3/18 ≒ 0.167 | 陽性予測のうち偽の割合、 1-Precision (fdr.html) |
| PPV | TP / (TP+FP) = Precision | 0.833 | 有病率に依存、 ベイズ後確率と一致 |
SSDSE-B-2026 47 県のような小規模 + ほぼ均衡 (16 vs 31) なケースでは、 ROC-AUC だけでなく PR-AUC と PPV/NPV を併記し、 行政コスト (誤って人口大県と判定した県への配分ミス) で閾値を調整するのが妥当である。
偽陽性 = 本当は陰性(無関係・健康・正常)なのに、 検査・分類器が陽性と判定してしまう誤り。 Type I error。 本ハンドブックでは数式・計算例・産業界事例・失敗例・演習・FAQ・50 連発レシピを一気通貫で提供する。 このハンドブックの数値は公的データ SSDSE-B-2026(独立行政法人 統計センター) を data/raw/SSDSE-B-2026.csv として読み込み、 2023 年・47 都道府県のレコードを集計したもの。
FPR(偽陽性率)は『本来陰性の集合のうち、 誤って陽性と判定された割合』。 有意水準 α と一致し、 仮説検定では通常 0.05 に設定されます。 ROC 曲線の横軸そのもの。
| 記号 | 意味 | SSDSE-B-2026 での例 |
|---|---|---|
FP | False Positive。 陰性なのに陽性判定 | 出生率 5.8‰ 未満だが高齢化率 32% 未満で『高齢化県』と誤判定された 11 県 |
TN | True Negative。 陰性を正しく陰性判定 | 高齢化率 32% 未満を正しく非高齢化と判定した数 |
FPR | FP/(FP+TN)。 陰性集団中の陽性率 | 本例では FP=11・TN=13 で FPR=11/24≈0.458 |
y | 真ラベル (0=陰性, 1=陽性) | true_aging = 1 if 高齢化率≥32% else 0 |
ŷ | 予測ラベル | pred_aging = 1 if 出生率<5.8‰ else 0 |
α | 有意水準=Type I error 確率 | 通常 0.05。 多重検定では Bonferroni 補正で α/m に縮小 |
47 都道府県を高齢化率(65 歳以上人口 A1303 ÷ 総人口 A1101)が 32% 以上なら『高齢化県 = 陽性』と定義します。 その予測に出生率(出生数 A4101 ÷ 総人口 A1101 × 1000)が 5.8‰ 未満という代理指標を使うと、 出生率は低いのに高齢化率は 32% 未満の県(埼玉・千葉など大都市圏)を『高齢化県』と誤判定します。 これが偽陽性です。
🎯 このコードでやること:SSDSE-B-2026 の 2023 年データで『出生率 5.8‰ 未満なら高齢化県(陽性)』と判定するルールの偽陽性を計算する(真ラベルは高齢化率 32% 以上)。
📥 入力データ:47 都道府県の 2023 年 A1101 総人口・A1303 高齢者人口・A4101 出生数。 真ラベル=高齢化率(A1303/A1101)が 32% 以上か。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) df23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101','A1303','A4101']].copy() d = df23.copy() d['aging'] = d['A1303']/d['A1101']*100 d['birth_rate'] = d['A4101']/d['A1101']*1000 d['true_aging'] = d['aging'] >= 32 # 真ラベル: 高齢化率 32% 以上 d['pred_aging'] = d['birth_rate'] < 5.8 # 予測: 出生率<5.8‰ → 高齢化と推定 TP = ((d.pred_aging) & (d.true_aging)).sum() FP = ((d.pred_aging) & (~d.true_aging)).sum() TN = ((~d.pred_aging) & (~d.true_aging)).sum() FN = ((~d.pred_aging) & (d.true_aging)).sum() print(f'TP={TP} FP={FP} TN={TN} FN={FN}') print(f'FPR (偽陽性率) = FP/(FP+TN) = {FP/(FP+TN):.3f}' if (FP+TN)>0 else 'TN=0') print(d[(d.pred_aging) & (~d.true_aging)][['Prefecture','birth_rate']]) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:高齢化率 32% 以上の県 (23) を出生率<5.8‰ で予測すると、 出生率は低いが高齢化率 32% 未満の県 11 件が偽陽性 (FP) となる。 FPR=11/24≈0.458。 代理指標の限界を示す好例。
47 都道府県を『出生率 5.8‰ 未満なら高齢化県(陽性)』とする単純ルールで予測した結果、 TP=18(正しく高齢化と予測)、 FP=11(誤って高齢化と予測)、 TN=13、 FN=5 となった。 高齢化率 32% 以上は 23 県、 未満は 24 県とほぼ均衡し、 FPR=11/24≈0.458 と偽陽性が多発している。 出生率という代理指標は高齢化の傾向を捉えるが、 大都市圏では出生率が低くても高齢化率は低いため FP が生じる。 balanced accuracy や PR-AUC も併用する。
| 真:高齢化 | 真:非高齢化 | |
|---|---|---|
| 予測:高齢化 | TP=18 | FP=11 |
| 予測:非高齢化 | FN=5 | TN=13 |
本ページの数値はすべて公的データ SSDSE-B-2026(独立行政法人 統計センター) を data/raw/SSDSE-B-2026.csv として読み込み、 2023 年・47 都道府県のレコードを集計したもの。
| 業種・領域 | 活用内容 | 代表事例 |
|---|---|---|
| 医療検診の腫瘍マーカー | CA19-9 など腫瘍マーカーは健常者でも 5% 程度が陽性閾値を越え偽陽性となる。 確定診断には画像・組織検査が必須。 | がん検診 |
| 空港セキュリティチェック | 金属探知機は鍵・ベルトでも反応し偽陽性が大量発生。 二次検査の人手を増やすトレードオフ。 | 国土交通省 航空保安 |
| クレジットカード不正検知 | 海外旅行で普段と違う場所での利用を不正と誤判定。 利用者の電話確認で実害を回避。 ROC 曲線で FP/TP のバランス調整。 | VISA/Mastercard |
| 迷惑メールフィルタ | 正規のメルマガを spam に誤分類。 受信者は『重要メールが届かない』と苦情。 FP を 1% 以下に抑える運用目標。 | Gmail/Outlook |
| 地震警報 (緊急地震速報) | 落雷ノイズや火山性微動を地震と誤検出した過去事例。 偽陽性は社会的影響が大きいため厳しく制御。 | 気象庁 |
| AI チャットの有害発言検出 | 皮肉・引用を有害と誤判定。 言論の自由とのバランスから FPR を年次でモニタリング。 | SNS プラットフォーム |
| 手法/概念 | 意味 | 主要パラメータ | 代表ユースケース | 備考 |
|---|---|---|---|---|
| 偽陽性 FP | 陰性を陽性と誤判定 | α / FPR | 迷惑メール過検出 | Type I error |
| 偽陰性 FN | 陽性を陰性と見逃し | β / FNR | がん見落とし | Type II error |
| 真陽性 TP | 陽性を正しく検出 | Recall | 感度の分子 | 求めたい結果 |
| 真陰性 TN | 陰性を正しく除外 | Specificity | 検査の的中除外 | FPR の分母 |
| 適合率 Precision | 陽性予測の正確さ | TP/(TP+FP) | FP を直接抑える | 高 P は低 FP を意味 |
| 再現率 Recall | 陽性の捕捉率 | TP/(TP+FN) | 見落とし削減 | FN を直接抑える |
| 失敗パターン | 発生メカニズム | 対処 |
|---|---|---|
| クラス不均衡で FPR が低くても精度低 | 陰性 99% のとき全部陰性予測でも accuracy 99%。 | Precision・Recall・F1・PR-AUC を併用。 SSDSE-B-2026 の人口減少データはまさにこの例。 |
| 複数検定で FPR が膨張 | 47 都道府県 × 多重検定で α=0.05 でも 2.3 件は偶然陽性。 | Bonferroni / Benjamini-Hochberg 補正を適用。 |
| ROC 曲線だけ見て閾値設定 | 陽性が稀な問題で AUC が高くても実運用で FP 多発。 | PR 曲線・Cost-sensitive 閾値最適化を併用。 |
| 検定の事後解釈で FPR を語る | 『p<0.05 なら 95% で正しい』は誤り。 FPR は事前確率。 | ベイズ的事後確率 P(H1|データ) と区別する。 |
解答の要点
日常の SSDSE-B-2026 分析でそのままコピペして使える 50 個のスニペット集。 1 行で完結するパターンを優先。
from sklearn.metrics import confusion_matrix; confusion_matrix(y, yhat)tn, fp, fn, tp = confusion_matrix(y, yhat).ravel()fpr = fp / (fp + tn)from sklearn.metrics import roc_curve; fpr, tpr, th = roc_curve(y, score)from sklearn.metrics import roc_auc_score; roc_auc_score(y, score)from sklearn.metrics import precision_recall_curve; p, r, t = precision_recall_curve(y, score)from sklearn.metrics import average_precision_score; average_precision_score(y, score)from sklearn.metrics import f1_score; f1_score(y, yhat)from sklearn.metrics import precision_score, recall_scorefrom sklearn.metrics import classification_report; print(classification_report(y, yhat))from statsmodels.stats.multitest import multipletests; multipletests(p_values, method='bonferroni')multipletests(p_values, method='fdr_bh')from scipy.stats import binomtest; binomtest(fp, fp+tn).pvaluefrom scipy.stats import beta; beta.ppf([0.025,0.975], fp+1, tn+1) # ベイズ CIimport numpy as np; ci = np.percentile([fpr_boot for _ in range(1000)], [2.5,97.5])from sklearn.calibration import calibration_curve; calibration_curve(y, score)from sklearn.isotonic import IsotonicRegression; IsotonicRegression().fit(score, y)from sklearn.linear_model import LogisticRegression; lr = LogisticRegression().fit(X, y)from sklearn.model_selection import cross_val_score; cross_val_score(lr, X, y, scoring='roc_auc')from sklearn.model_selection import StratifiedKFold; for tr,te in StratifiedKFold(5).split(X,y): ...df['pred'] = (df['score']>0.5).astype(int)df['fp_flag'] = (df.pred==1) & (df.y==0)df.groupby('group').apply(lambda g: ((g.pred==1)&(g.y==0)).mean()) # subgroup FPRnp.where(score>th, 1, 0)(yhat & ~y).sum() / (~y).sum() # FPR(yhat & y).sum() / y.sum() # Recall(yhat & y).sum() / yhat.sum() # Precisionimport seaborn as sns; sns.heatmap(confusion_matrix(y,yhat), annot=True)from sklearn.metrics import balanced_accuracy_score; balanced_accuracy_score(y, yhat)from sklearn.metrics import matthews_corrcoef; matthews_corrcoef(y, yhat)from sklearn.metrics import cohen_kappa_score; cohen_kappa_score(y, yhat)from sklearn.metrics import log_loss; log_loss(y, score)from sklearn.metrics import brier_score_loss; brier_score_loss(y, score)fpr_target = 0.05; th = np.percentile(score[y==0], (1-fpr_target)*100)from sklearn.svm import OneClassSVM; OneClassSVM().fit(X[y==0])from sklearn.ensemble import IsolationForest; IsolationForest().fit_predict(X)df['decile'] = pd.qcut(df.score, 10, labels=False)df.groupby('decile').agg(rate=('y','mean'), n=('y','size'))import shap; shap.summary_plot(shap.Explainer(model)(X), X)from sklearn.inspection import permutation_importance; permutation_importance(model, X, y)from sklearn.model_selection import GridSearchCV; GridSearchCV(lr, {'C':[0.1,1,10]}).fit(X,y)from imblearn.over_sampling import SMOTE; SMOTE().fit_resample(X, y)from imblearn.under_sampling import RandomUnderSampler; RandomUnderSampler().fit_resample(X, y)model.predict_proba(X)[:,1]np.linspace(0,1,101)from sklearn.metrics import auc; auc(fpr, tpr)matplotlib.pyplot.plot(fpr, tpr); plt.xlabel('FPR'); plt.ylabel('TPR')plt.fill_between(fpr, tpr, alpha=0.2)from sklearn.metrics import det_curve; det_curve(y, score)from sklearn.metrics import precision_recall_fscore_support; precision_recall_fscore_support(y, yhat)本章では SSDSE-B-2026 の 47 都道府県を題材に、 FP/FN/TP/TN の混同行列から始まり、 ROC/PR/F1/MCC/Calibration/多重検定補正 までを実値計算で総点検する。 クラス構成(陽性 49% vs 陰性 51%)のほぼ均衡した高齢化ラベルで検証する。
🎯 このコードでやること:47 都道府県の出生率を閾値 5.8‰ で『高齢化県(高齢化率 32% 以上)』と予測し、 混同行列・FPR・Precision・Recall・F1を一気に計算する。
📥 入力データ:SSDSE-B-2026 2023 年の 47 行(人口 A1101, 高齢者 A1303, 出生数 A4101)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) df23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101','A1303','A4101']].copy() d = df23.copy() d['aging'] = d['A1303']/d['A1101']*100 d['birth_rate'] = d['A4101']/d['A1101']*1000 y = (d['aging'] >= 32).astype(int) yhat = (d['birth_rate'] < 5.8).astype(int) TP = int(((yhat==1)&(y==1)).sum()); FP = int(((yhat==1)&(y==0)).sum()) TN = int(((yhat==0)&(y==0)).sum()); FN = int(((yhat==0)&(y==1)).sum()) prec = TP/(TP+FP) if TP+FP else float('nan') rec = TP/(TP+FN) if TP+FN else float('nan') f1 = 2*prec*rec/(prec+rec) if prec+rec else float('nan') print(f'TP={TP} FP={FP} TN={TN} FN={FN}') print(f'Precision={prec:.3f} Recall={rec:.3f} F1={f1:.3f}') |
📤 実行結果:
💬 結果の読み方:Precision 62%・Recall 78%。 陽性予測 29 件のうち 11 件 (38%) が偽陽性で、 高齢化県でない県を高齢化と誤判定している。 閾値 (5.8‰) を下げれば FP↓だが FN↑。 業務コストで閾値を決めるのが王道。
🎯 このコードでやること:ROC 曲線と AUC を計算し、 出生率を連続スコアとして使ったときの判別力を測る。
📥 入力データ:上記 d(47 行)。 score = -birth_rate(小さいほど陽性傾向)。
1 2 3 4 5 6 7 8 | from sklearn.metrics import roc_curve, roc_auc_score score = -d['birth_rate'].values # 出生率が低いほど高齢化スコア大 fpr, tpr, th = roc_curve(y, score) auc = roc_auc_score(y, score) print(f'AUC = {auc:.3f}') print('閾値毎の (FPR, TPR) 抜粋:') for i in [1, len(fpr)//4, len(fpr)//2, 3*len(fpr)//4, -1]: print(f' th={-th[i]:.2f}‰ FPR={fpr[i]:.2f} TPR={tpr[i]:.2f}') |
📤 実行結果:
💬 結果の読み方:AUC=0.707 は 0.5 を上回り、 『出生率が低い県ほど高齢化率が高い』傾向を確かに捉えている。 ただし完全ではなく、 FPR を上げないと TPR が伸びない領域があり、 出生率だけでは高齢化の判別に偽陽性が伴う。
陽性 1% × 感度 95% × 特異度 95% でも PPV は 16%。 検査結果の解釈には事前確率が不可欠。
47 都道府県を α=0.05 で個別検定すると、 偶然陽性が 2.35 件出る期待値。 補正後の α=0.001 で抑える。
FDR を制御。 Bonferroni より緩いがパワーが高い。 ゲノム解析などで標準。
FP の業務コスト C_FP、 FN の業務コスト C_FN を見積もり、 期待損失を最小化する閾値を選ぶ。
Platt scaling / Isotonic regression で予測確率=実頻度を保証。 SHAP よりまず Calibration を見るべき。
Demographic Parity / Equalized Odds はサブグループ別の FPR/TPR が均等かを測る。 GDPR・AI 規制で重要度増。
| 項目 | 参考値 | 備考 |
|---|---|---|
| 感度 95% 特異度 95% prevalence 1% | PPV 16% | 基準率の誤謬の典型例 |
| 感度 95% 特異度 99% prevalence 1% | PPV 49% | 特異度を上げると PPV 急上昇 |
| 感度 99% 特異度 95% prevalence 50% | PPV 95% | 高有病率なら感度重視 |
| Bonferroni m=47 α=0.05 | α'=0.001 | 厳しすぎる |
| BH 法 m=47 FDR=0.05 | α'≈0.02-0.05 | 適度な保護 |
| ROC-AUC ベースライン | 0.5 | ランダム |
| PR-AUC ベースライン | prevalence | 不均衡時は AUC=陽性率 |
本パートでは偽陽性 (FP) 関連の評価コード 30 個を、 scikit-learn / statsmodels / imbalanced-learn を中心に整理する。 47 都道府県データを題材に Calibration / Bootstrap CI / Subgroup 監査まで実装する。
🎯 このコードでやること:ROC-AUC と PR-AUC をBootstrap で 1000 回計算し、 95% 信頼区間を作る。
📥 入力データ:47 都道府県の出生率 (連続スコア) と『高齢化率 32% 以上』ラベル。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd, numpy as np from sklearn.metrics import roc_auc_score, average_precision_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) df23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101','A1303','A4101']].copy() d = df23.copy() d['aging'] = d['A1303']/d['A1101']*100 y = (d['aging'] >= 32).astype(int).values score = -(d['A4101']/d['A1101']).values # 出生率が低いほど高齢化スコア大 rng = np.random.default_rng(0) auc_boot, ap_boot = [], [] for _ in range(1000): idx = rng.integers(0, len(y), len(y)) if len(set(y[idx])) == 2: auc_boot.append(roc_auc_score(y[idx], score[idx])) ap_boot.append(average_precision_score(y[idx], score[idx])) print(f'ROC-AUC = {np.mean(auc_boot):.3f} 95% CI = [{np.percentile(auc_boot,2.5):.3f}, {np.percentile(auc_boot,97.5):.3f}]') print(f'PR-AUC = {np.mean(ap_boot):.3f} 95% CI = [{np.percentile(ap_boot,2.5):.3f}, {np.percentile(ap_boot,97.5):.3f}]') |
📤 実行結果:
💬 結果の読み方:ROC-AUC 0.706、 95% CI [0.544, 0.850] は 0.5 を上回るので、 出生率は高齢化の予測に有意な情報を持つ。 PR-AUC 0.749 は陽性率(base rate ≈ 0.49)を明確に上回り、 単なる多数派予測より優れる。 ただし FPR≈0.46 と偽陽性は多く、 閾値調整が要る。
| # | 構文・関数 | 用途 |
|---|---|---|
| ①01 | from sklearn.metrics import confusion_matrix | 混同行列 |
| ①02 | tn,fp,fn,tp = confusion_matrix(y,yhat).ravel() | 4 セル取り出し |
| ①03 | fpr = fp/(fp+tn) | FPR 計算 |
| ①04 | tpr = tp/(tp+fn) # = recall | TPR / Recall |
| ①05 | precision = tp/(tp+fp) | Precision |
| ①06 | f1 = 2*p*r/(p+r) | F1 |
| ①07 | from sklearn.metrics import roc_curve | ROC 曲線 |
| ①08 | from sklearn.metrics import roc_auc_score | ROC-AUC |
| ①09 | from sklearn.metrics import precision_recall_curve | PR 曲線 |
| ①10 | from sklearn.metrics import average_precision_score | PR-AUC |
| ②11 | from sklearn.metrics import classification_report | 総合レポート |
| ②12 | from sklearn.metrics import balanced_accuracy_score | 不均衡対応 acc |
| ②13 | from sklearn.metrics import matthews_corrcoef | MCC |
| ②14 | from sklearn.metrics import cohen_kappa_score | Kappa |
| ②15 | from sklearn.metrics import log_loss | 対数損失 |
| ②16 | from sklearn.metrics import brier_score_loss | Brier |
| ②17 | from sklearn.calibration import calibration_curve | キャリブレーション |
| ②18 | from sklearn.calibration import CalibratedClassifierCV | 確率校正器 |
| ②19 | from sklearn.isotonic import IsotonicRegression | Isotonic 校正 |
| ②20 | from statsmodels.stats.multitest import multipletests | 多重検定補正 |
| ③21 | multipletests(pvals, method='bonferroni') | Bonferroni |
| ③22 | multipletests(pvals, method='fdr_bh') | BH 法 |
| ③23 | from scipy.stats import binomtest | 二項検定 |
| ③24 | from imblearn.over_sampling import SMOTE | オーバサンプリング |
| ③25 | from imblearn.under_sampling import RandomUnderSampler | アンダーサンプリング |
| ③26 | GridSearchCV(clf, {'C':[0.1,1,10]}, scoring='roc_auc') | ハイパラ最適化 |
| ③27 | permutation_importance(clf, X, y) | 重要度 |
| ③28 | shap.Explainer(clf)(X) | SHAP |
| ③29 | Equalized Odds via fairlearn.metrics | 公平性監査 |
| ③30 | DriftDetector(ref, current) | ドリフト検知 |
ここまで偽陽性(false positive, FP)の定義・指標・閾値・コスト最適化を扱った。 ここでは SSDSE-B-2026 都道府県データを使った 9 つの追加トピックを順に提示する。 演習問題 → 図 3 枚 → 医療/詐欺/公平性/ベイズ/歴史/英訳/学習リソースを連結させ、 「偽陽性を 1 つの章として習得する」構成にしている。
以下の練習問題を 1 問ずつ自分で解いてから解答を確認すること。 答えを暗記するのでなく、 「なぜそうなるか」を SSDSE-B-2026 のデータ感覚と紐づけて理解するのが狙いである。 制限時間の目安は全 10 問で 20 分。 まずは紙とペンで結論を出し、 そのうえで Python を動かして数値を確かめる。
以下 3 枚は SSDSE-B-2026 都道府県データに基づいて作成した分布と関係の図である。 偽陽性は「分布の裾」「閾値の置き場所」「群間比較」の 3 つの観点でしばしば発生する。 図と本文を見比べながら「どの場合に FP が増えるか」を直感で掴んでほしい。
図 1. SSDSE 散布図 — 人口と出生数の関係
📊 2023 年度の 47 都道府県の人口(横軸)と出生数(縦軸)。 r = 0.995 の強い正の相関で、 出生数に「平均 + 2σ(49.8 千人)を超えたら異常」という閾値を機械的に当てると東京・神奈川・大阪の 3 都府県が陽性になる。 しかし人口千人当たりの出生数は東京 6.13・大阪 6.31・神奈川 5.85 で全国値 5.85 と変わらず、 「異常な大都市」ではなく実態どおり大きいだけのため、 文脈上の偽陽性になり得る。 閾値カットの前に必ず散布図を見ること。
図 2. 都道府県人口のヒストグラム
📊 2023 年度の 47 都道府県の人口分布(平均 264.6 万人・標準偏差 279.8 万人・中央値 154.9 万人)。 右に裾を引く対数正規的形状で、 平均と標準偏差から正規分布を仮定して外れ値を切ると、 「3σ ルール」(1,104 万人超)では東京だけ、 「2σ ルール」(824 万人超)では東京・神奈川・大阪が機械的に陽性となる。 標準偏差そのものが東京に引っ張られて大きいので、 どの k を選ぶかで陽性の顔ぶれが変わる。 これは分布の歪みが大きい場合に起こる典型的な偽陽性で、 IQR や対数変換、 ロバスト統計の利用で回避できる。
図 3. 地域ブロック別 箱ひげ図
📊 2023 年度の総人口を地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州・沖縄)に分けた箱ひげ図。 全国共通の閾値「平均 + 1σ = 544 万人」を当てると、 陽性 6 県のうち 4 県(埼玉・千葉・東京・神奈川)が関東 7 県に集中し、 残りは中部の愛知と近畿の大阪だけで、 四国(中央値 81 万人)などは 1 県も陽性にならない。 関東で「異常」が多いのではなくブロックごとの水準(中央値は関東 626 万人・四国 81 万人)が違うだけなので、 同じ閾値を全国に当てると関東では偽陽性が増え、 小さいブロックでは本当の異常を見逃しやすい。 群ごとに base rate が違うので、 群ごと閾値(per-group threshold)または階層モデルでの補正が必要となる。
医療では偽陽性が最も多くの議論を呼ぶ。 ここでは 3 つの代表的ケースを表で整理する。 いずれも「感度 vs 特異度 vs base rate」のトレードオフが鍵で、 検査の精度よりも罹患率の方が PPV を支配することが多い。
| 検査 | 罹患率 | 感度 | 特異度 | PPV | 解釈 |
|---|---|---|---|---|---|
| マンモグラフィ(40歳代) | 0.4% | 85% | 90% | 3.3% | 陽性者の 97% は偽陽性 |
| PSA(前立腺癌) | 3% | 75% | 85% | 13.4% | 陽性者の 86% は偽陽性 |
| COVID-19 PCR(流行期) | 5% | 95% | 99% | 83.3% | 陽性者の 17% が偽陽性 |
| HIV ELISA(高リスク群) | 10% | 99% | 99% | 91.7% | 陽性者の 8% が偽陽性 |
| HIV ELISA(低リスク群) | 0.1% | 99% | 99% | 9.0% | 陽性者の 91% は偽陽性 |
| 大腸内視鏡(症状あり) | 15% | 95% | 85% | 52.8% | 陽性者の半数は偽陽性 |
💡 上記から読めるのは「罹患率が低い集団で広く検査をすると、 たとえ高精度な検査でも陽性の大半が偽陽性になる」事実である。 これは Bayes の定理が直接示す結果で、 検査前確率(事前確率)を上げる、 つまり「症状やリスクで集団を絞る」のが PPV 改善の王道。 集団的スクリーニングを設計する際は、 必ず PPV を Bayes 計算で見積もる。
詐欺検知は陽性率(fraud rate)が極端に低い(0.1% 程度)不均衡問題の典型である。 偽陽性は「顧客体験悪化」「カード一時停止」「コンタクトセンター負荷増」につながり、 FN(見逃し)は直接的な金銭損失につながる。 両者のコスト比で閾値を選ぶ。
| ドメイン | 陽性率 | FP コスト | FN コスト | 推奨閾値 |
|---|---|---|---|---|
| クレジット詐欺 | 0.1% | 確認電話 200 円 | 不正額平均 50,000 円 | 0.005-0.02 |
| メールスパム | 20% | 重要メール紛失(大) | 迷惑メール受信(小) | 0.7-0.95(高めに) |
| 不正ログイン | 0.05% | MFA 追加要求(中) | アカウント乗っ取り(大) | 0.01-0.05 |
| マネーロンダリング | 0.01% | 調査人件費 5,000 円 | 規制罰金 数千万円 | 0.001-0.01 |
| EC レビュー操作検出 | 3% | 健全レビュー削除(中) | サクラ放置(中) | 0.4-0.6 |
💡 詐欺検知では「閾値 0.5」はほぼ常に間違い。 ベースラインの陽性率と業務コストから「最適閾値」を導出し、 半年ごとにモニタリングして再調整する。 ライフサイクル管理(MLOps)が偽陽性制御の鍵。
同じモデルでも、 サブグループ(性別・年代・地域)別に偽陽性率は変わる。 これが公平性違反になるかは、 採用シナリオ次第で判定が異なる。 SSDSE-B-2026 のような都道府県データでも「地域ブロック別 FPR」を必ず確認する習慣が必要。
| 公平性指標 | 数式 | 意味 | FP との関係 |
|---|---|---|---|
| Demographic Parity | P(ŷ=1|A=a)=P(ŷ=1|A=b) | 陽性率の平等 | 間接的 |
| Equal Opportunity | TPR_a = TPR_b | 真陽性率の平等 | 補集合に注意 |
| Equalized Odds | TPR_a = TPR_b ∧ FPR_a = FPR_b | TPR/FPR の同時平等 | FPR 直接制約 |
| Predictive Parity | PPV_a = PPV_b | 陽性的中率の平等 | FP 数の比率に影響 |
| Calibration | P(y=1|p=q, A=a) = q | 確率の解釈一致 | 確率ベース FP |
| Treatment Equality | FN_a/FP_a = FN_b/FP_b | エラー比率の平等 | FP/FN バランス |
💡 Chouldechova (2017) と Kleinberg et al. (2017) の不可能定理により、 base rate が群間で異なる場合、 上記公平性指標を 同時に満たすことは不可能。 業務上どれを優先するかを明示的に選ばなければならない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd, numpy as np from sklearn.metrics import confusion_matrix df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=1, encoding='cp932') # 行は「県ごとに 2023→2012 の降順」で並んでいる。 # そのまま diff() を取ると (a) 県の境目をまたぐ (b) 新しい年から古い年を引くので符号が逆、 # の 2 つが同時に起きる。 県ごとに年度昇順へ並べ替えてから差分を取る。 df = df.sort_values(['都道府県', '年度']) df['増減'] = df.groupby('都道府県')['総人口'].diff() df = df.dropna(subset=['増減']) # 2012 年度は前年が無いので除く (2013〜2023 の 517 行) df['人口減少'] = (df['増減'] < 0).astype(int) df['ブロック'] = df['都道府県'].map({'北海道':'北海道','青森県':'東北','岩手県':'東北','宮城県':'東北','秋田県':'東北','山形県':'東北','福島県':'東北'}).fillna('その他') df['予測'] = (df['合計特殊出生率'] < 1.3).astype(int) if '合計特殊出生率' in df.columns else 0 for blk, sub in df.groupby('ブロック'): tn,fp,fn,tp = confusion_matrix(sub['人口減少'], sub['予測'], labels=[0,1]).ravel() fpr = fp/(fp+tn) if (fp+tn) else float('nan') print(f'ブロック {blk}: 件数 {len(sub)}, 減少なし {fp+tn}, FP {fp}, FPR = {fpr:.3f}') |
📤 実行結果(例):
💬 結果の読み方: FPR の分母は「実際には人口が減っていない県・年」の件数で、 その他ブロックは 68 件あり、 そのうち出生率 1.3 未満で「減少」と誤判定された 16 件 (東京都の 10 年分と、 千葉・埼玉・神奈川の 2019〜2020 年度) で FPR = 0.235。 東北は分母が宮城県の 2 件しかなく FPR = 0.000、 北海道は 11 年間ずっと人口が減っているので分母が 0 で FPR は計算できない (nan)。 前年が無い 2012 年度を差 0 (=減少なし) として残すと、 北海道にも架空の「減少なし」が 1 件でき、 それが偽陽性になって FPR = 1.000 と出てしまう。 群ごとの比率は分母の件数と並べて読み、 件数の少ない群には信用区間を付ける (次節のベイズ的アプローチ)。
FPR を「点推定 0.05」と報告するのではなく、 事後分布として扱うとサンプル数の少なさによる不確実性が明示できる。 Beta-Binomial モデルが標準的で、 prior を Beta(1,1)(無情報)とし、 観測 FP=4, TN=8 なら事後は Beta(5, 9)。 95% 信用区間は分位点から直接計算できる。
1 2 3 4 5 6 7 8 | import numpy as np from scipy import stats fp, tn = 4, 8 # 観測値 a, b = 1+fp, 1+tn # Beta 事後パラメータ post = stats.beta(a, b) print(f'事後平均 = {post.mean():.3f}') print(f'95% 信用区間 = [{post.ppf(0.025):.3f}, {post.ppf(0.975):.3f}]') print(f'FPR>0.5 の事後確率 = {1-post.cdf(0.5):.3f}') |
📤 実行結果:
💬 結果の読み方: サンプル数 12 しかない場合、 点推定 FPR=0.333 だけ見せるより 95% 信用区間 [0.139, 0.614] を併記すべき。 「FPR が 50% を超える可能性が 13.3% 残る」と読み取れる。 ベイズは少ない観測でも誤解を生みにくい言葉を提供する。
| 年 | 人物・出来事 | 貢献 |
|---|---|---|
| 1763 | Bayes / Price | 事後確率の概念 — PPV 計算の理論基盤 |
| 1928 | Neyman & Pearson | Type I / Type II error の定式化(FP=Type I) |
| 1941 | RADAR ROC 曲線 | 第二次大戦中、 信号検知のため ROC が誕生 |
| 1961 | Tanner & Swets | signal detection theory として体系化 |
| 1995 | Benjamini & Hochberg | FDR 概念導入 — 多重比較で FP 管理 |
| 2006 | Hand | 分類器の「H-measure」提案、 AUC の批判 |
| 2016 | ProPublica COMPAS 報告 | 人種別 FPR 格差が司法 AI 公平性議論を加速 |
| 2018 | Chouldechova 不可能定理 | 公平性指標の同時満足不可を証明 |
| 日本語 | 英語 | 補足 |
|---|---|---|
| 偽陽性 | false positive (FP) / Type I error | 「あわてんぼうの誤り」 |
| 偽陰性 | false negative (FN) / Type II error | 「ぼんやりの誤り」 |
| 真陽性 | true positive (TP) | 正しく陽性 |
| 真陰性 | true negative (TN) | 正しく陰性 |
| 偽陽性率 | false positive rate (FPR) | FP/(FP+TN) = 1-specificity |
| 特異度 | specificity / true negative rate | TN/(TN+FP) |
| 陽性的中率 | positive predictive value (PPV) | TP/(TP+FP) = precision |
| 陰性的中率 | negative predictive value (NPV) | TN/(TN+FN) |
| 族関連誤発見率 | family-wise error rate (FWER) | Bonferroni が制御 |
| 偽発見率 | false discovery rate (FDR) | BH 法が制御 |
| 確率校正 | probability calibration | Platt / Isotonic |
| 公平性指標 | fairness metric | Equalized Odds 等 |
偽陰性 / 適合率 / 再現率 / 特異度 / AUC / ROC 曲線 / 混同行列 / F1 スコア / p 値 / 多重比較 / FDR / 対立仮説 / クラス不均衡 / 分類 / ロジスティック回帰 / 決定木 / ランダムフォレスト / 交差検証 / ブートストラップ / 公平性 / SHAP
偽陽性率 FPR は 1-specificity と等しく、 ROC 曲線の横軸そのものでもある。 ここでは混同行列の 4 セル(TP, TN, FP, FN)から派生する主要指標 12 種を、 計算式と意味を併記して整理する。 同じ実験データに対して指標値を一斉に出すと、 不均衡や閾値の影響が浮き彫りになる。
| 指標 | 英名 | 数式 | 意味・補足 |
|---|---|---|---|
| 偽陽性率 | FPR | FP/(FP+TN) | ROC 横軸、 type I error |
| 真陽性率 | TPR / recall | TP/(TP+FN) | ROC 縦軸、 検出力 |
| 特異度 | specificity / TNR | TN/(TN+FP) | = 1-FPR |
| 適合率 | precision / PPV | TP/(TP+FP) | 陽性出力の信頼度 |
| 陰性的中率 | NPV | TN/(TN+FN) | 陰性出力の信頼度 |
| FDR | false discovery rate | FP/(TP+FP) = 1-precision | 陽性中の偽の割合 |
| FOR | false omission rate | FN/(TN+FN) = 1-NPV | 陰性中の偽の割合 |
| F1 | F1 score | 2·P·R/(P+R) | precision と recall の調和平均 |
| 尤度比+ | LR+ | TPR/FPR | 陽性検査結果の尤度比 |
| 尤度比- | LR- | FNR/TNR | 陰性検査結果の尤度比 |
| バランス精度 | balanced accuracy | (TPR+TNR)/2 | 不均衡時に使う accuracy |
| MCC | Matthews correlation | (TP·TN-FP·FN)/√(...) | 不均衡対応の総合指標 |
💡 これらの指標は互いに代数的に結び付いている。 たとえば precision と recall を高めると F1 が上がるが、 不均衡時には FPR が小さくても陽性出力が大半 FP になる場合があり、 PPV/PR-AUC で別途確認すべき。 単一指標を金科玉条にせず、 複数指標の組合せで意思決定する。
FPR を最小化するためには、 単純にクラス重み付けや SMOTE だけではなく、 確率校正(calibration)と組み合わせる必要がある。 校正されていない確率の閾値を 0.1 に下げても、 元のスコア分布がいびつだと FP が安定的に減らない。 以下は SSDSE-B-2026 を題材にした典型的なパイプライン。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import pandas as pd, numpy as np from sklearn.linear_model import LogisticRegression from sklearn.calibration import CalibratedClassifierCV from sklearn.metrics import classification_report, roc_curve df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=1, encoding='cp932') # 行は「県ごとに 2023→2012 の降順」で並んでいる。 # そのまま diff() を取ると (a) 県の境目をまたぐ (b) 新しい年から古い年を引くので符号が逆、 # の 2 つが同時に起きる。 県ごとに年度昇順へ並べ替えてから差分を取る。 df = df.sort_values(['都道府県', '年度']) df['増減'] = df.groupby('都道府県')['総人口'].diff() df = df.dropna(subset=['増減']) # 2012 年度は前年が無いので除く (2013〜2023 の 517 行) y = (df['増減'] < 0).astype(int) X = df[['総人口','出生数']].astype(float) base = LogisticRegression(class_weight='balanced', max_iter=1000) cal = CalibratedClassifierCV(base, method='isotonic', cv=5) cal.fit(X, y) prob = cal.predict_proba(X)[:,1] fpr, tpr, thr = roc_curve(y, prob) target_fpr = 0.05 # FPR を 5% 以下に抑える idx = np.argmax(fpr > target_fpr) - 1 # 5% を超える直前の閾値 chosen = thr[idx] yhat = (prob >= chosen).astype(int) print(f'選択閾値 = {chosen:.3f}, 実 FPR = {fpr[idx]:.3f}, TPR = {tpr[idx]:.3f}') print(classification_report(y, yhat, digits=3)) |
📤 実行結果(例):
💬 結果の読み方: FPR を 5% 以下に抑える閾値 0.883 を選ぶと、 人口が減らなかった 70 件のうち誤って「減少」と判定したのは 3 件 (実 FPR = 0.043) で、 減少した 447 件のうち 388 件 (TPR = 0.868) を拾えている。 517 件中 447 件 (86%) が「減少あり」の不均衡データなので、 全部を「減少あり」と答えるだけで accuracy 0.865 が出てしまい、 accuracy 0.880 はそれとほとんど変わらない。 閾値を動かしたときは accuracy ではなく FPR と TPR の組で評価する。 なお校正と閾値選びを同じ 517 件で行っているので、 新しい年度では FPR が 5% を超えることもありうる。
モデルを本番投入したら、 FPR は時間とともに変動する(drift)。 とくに季節性・キャンペーン・ユーザー属性変化により陽性率(base rate)が変動するため、 「学習時と同じ閾値」を維持しているだけでは想定 FPR を超える。 以下は典型的なモニタリング指標。
| 指標 | 監視頻度 | アラート閾値の例 | 対応アクション |
|---|---|---|---|
| FPR | 毎時 | 学習時 +2σ 超 | 閾値再キャリブレーション |
| 陽性率 | 毎時 | 過去 7 日平均から ±30% | 入力ドリフト調査 |
| PSI | 日次 | PSI > 0.2 | 特徴量分布の変化を分析 |
| KS 統計量 | 日次 | D > 0.1 | 分布ドリフト評価 |
| サブグループ FPR | 週次 | 群間差 > 2 倍 | 公平性レビュー実施 |
| Calibration Error | 週次 | ECE > 0.05 | Isotonic 再校正 |
sklearn.metrics.roc_curve で FPR と TPR を得て matplotlib でプロット。 さらに auc() で面積、 RocCurveDisplay で凡例も自動表示できる。shap_values を計算して force_plot や waterfall で寄与の大きい特徴量を可視化する。 共通パターンが見えれば特徴量改善のヒントになる。| 用語 | 英語 | 説明 |
|---|---|---|
| Youden's J | Youden index | J = TPR - FPR、 ROC 上で最大点を閾値に |
| 事前確率 | prior probability | base rate と同義、 Bayes 計算の出発点 |
| 事後確率 | posterior probability | 検査結果を踏まえた更新後の確率 |
| アラート疲れ | alert fatigue | FP 多発によるオペレータ感度低下 |
| α エラー | alpha error | Type I error の別名 |
| β エラー | beta error | Type II error の別名 |
| PSI | Population Stability Index | 分布の変化を測る、 ドリフト検知の標準 |
| KS 距離 | Kolmogorov-Smirnov | 分布間距離、 ドリフト検知に利用 |
| Brier スコア | Brier score | 確率予測の二乗誤差、 校正評価 |
| ECE | Expected Calibration Error | 校正誤差の平均、 0 に近いほど良い |
| disparate impact | 不利益的影響 | 米国法で公平性違反の指標、 4/5 ルール |
| cost matrix | コスト行列 | FP/FN それぞれにコスト割当 |
| Platt 校正 | Platt scaling | ロジスティック回帰で確率校正 |
| Isotonic 校正 | Isotonic regression | 単調回帰で確率校正 |
| 事例ベース監査 | case-based audit | FP 事例の質的分析 |
ストーリー 1: 健康診断の不安
健康診断で「腫瘍マーカー陽性」と通知された 40 代男性。 病院での精密検査の結果、 良性であった。 これが偽陽性の典型例。 罹患率 0.5%、 感度 80%、 特異度 90% の検査ならば PPV ≈ 3.9%。 つまり陽性通知を受けた人のうち約 96% は実際には罹患していない。 検査前にこの数字を知っておけば、 不必要な不安は減らせる。 医療リテラシーとして PPV を知る意味は大きい。
ストーリー 2: スパムメールの誤判定
大手 EC 企業の重要な確認メールが、 顧客の Gmail スパムフォルダに自動振り分けされ続けた。 これは顧客側スパム分類器の偽陽性。 顧客から「届かない」と苦情が続出。 SPF / DKIM / DMARC を整え、 送信ドメインの reputation を高めることで FPR を下げた。 メール業界では「FP 0.1% でも 100 万通中 1,000 通が誤判定」と認識する。
ストーリー 3: 顔認証の入退室管理
オフィスの顔認証ゲートで、 双子の弟が兄として誤認識(FP)された。 セキュリティ部門は「FPR < 0.001%」を保証していたが、 双子のような外れ値で破綻。 解決策はマルチモーダル認証(顔+IC カード)と、 サブグループ別 FPR の継続監査。 「全体平均」だけ見ても安全とは言えない好例。
| アンチパターン | なぜダメか | 代わりに |
|---|---|---|
| accuracy だけで評価 | 不均衡で誤導的 | F1, PR-AUC, MCC を併用 |
| 閾値 0.5 固定 | 業務コスト無視 | コスト最適化で決定 |
| テスト側にも SMOTE | 評価が壊れる | 訓練のみに適用 |
| 校正なしの確率閾値 | 出力確率が信頼できない | Platt / Isotonic 校正 |
| 多重比較補正なし | FP が量産される | Bonferroni / BH 法 |
| 全体 FPR のみ公開 | サブグループ格差を隠蔽 | group-wise FPR を必須報告 |
| 本番でも訓練時閾値固定 | ドリフトで FPR 上昇 | 定期再校正 |
| 「FPR=0」と宣伝 | 物理的に不可能 | 定量的に明示する |
「偽陽性」という言葉は同じでも、 産業によってその意味と扱いは大きく異なる。 ここでは 12 業界での代表例を表でまとめる。 自分の業界がどこに該当するかを意識し、 「許容できる FPR の水準」と「FP の社会的・経済的コスト」を見極める素材として使ってほしい。
| 業界 | 陽性の意味 | FP の主なコスト | 許容 FPR の目安 |
|---|---|---|---|
| 医療診断 | 疾患疑い | 精密検査負担・心理的不安 | 5-15% |
| 医薬品開発 | 候補化合物 | 無駄な開発費(億単位) | 1% 以下 |
| クレジット不正 | 疑わしい取引 | 確認電話・顧客不満 | 0.5-2% |
| マネロン検知 | SAR 報告候補 | 調査工数増 | 1-5% |
| サイバーセキュリティ | 攻撃疑い | アラート疲れ | 0.1-1% |
| スパムフィルタ | スパム判定 | 重要メール紛失 | 0.01-0.1% |
| 空港セキュリティ | 危険物疑い | 追加検査・遅延 | 5-20% |
| 司法 AI(再犯予測) | 再犯リスク | 不当な拘束・倫理問題 | 慎重設計必須 |
| 採用 AI | 不適合候補 | 差別・機会損失 | 公平性監査必須 |
| 広告ターゲティング | 関心ありユーザー | 配信費の無駄 | 業務 ROI 次第 |
| 天気予報(豪雨) | 豪雨警報 | 警報疲れ・経済損失 | 10-30% |
| 天文学(系外惑星) | 候補天体 | 追跡観測の浪費 | 5-15% |
💡 同じ「偽陽性 5%」でも、 医療スクリーニングなら許容範囲、 マネロン検知なら過大、 採用 AI なら社会問題。 数字だけで評価せず、 「業界規範」「規制」「ユーザー体験」を踏まえる必要がある。
偽陽性 (False Positive, FP) は混同行列の 4 セルのうちの 1 つで、 「実際は陰性なのに陽性と予測した」誤りを指す。 同義: Type I Error、 α エラー、 False Alarm。 SSDSE-B-2026 を題材にすれば、 「失業率の高い県」と予測したが実際は中程度だった、 などが FP に該当する。
【混同行列 (Confusion Matrix) の 4 セル】
予測: 陽性 (+) 予測: 陰性 (-)
┌─────────────────────┬─────────────────────┐
実際: 陽性 │ TP (真陽性) │ FN (偽陰性 / Type II) │
│ 正しく陽性と予測 │ 陽性を見逃した │
├─────────────────────┼─────────────────────┤
実際: 陰性 │ FP (偽陽性) ★ │ TN (真陰性) │
│ 本ページ │ 正しく陰性と予測 │
│ 陰性を陽性と誤判定 │ │
└─────────────────────┴─────────────────────┘
【FP と関連指標の対応】
偽陽性数 FP ──┬─→ FPR = FP / (FP + TN) ─ 特異度 = 1 - FPR
├─→ Precision = TP / (TP + FP) ─ FP 増 → Precision 低下
├─→ Type I Error 確率 α ─ 統計検定: 帰無棄却の誤り
├─→ ROC 曲線 X 軸 ─ FPR をプロット
└─→ FDR = FP / (TP + FP) ─ 多重検定での累積誤発見率
【上位概念ツリー】
分類モデルの誤り
├─ 偽陽性 (FP) ★ 本ページ ─ Type I / α エラー / False Alarm
│ ├─ Bonferroni 補正 ─ 多重検定での α 調整
│ ├─ Holm 法 ─ 段階的 α 調整
│ └─ FDR (BH 法) ─ 累積偽陽性率制御
└─ 偽陰性 (FN) ─ Type II / β エラー / Miss
├─ 検出力 (Power = 1-β)
└─ 標本サイズ設計
【ドメイン別の許容 FP】
医療スクリーニング ─ 高 FP 許容 (見逃し回避優先)
詐欺検知 ─ 低 FP 必須 (顧客体験悪化)
天文台候補天体 ─ 中 FP 許容 (追跡観測で再確認)
迷惑メール判定 ─ 極低 FP 必須 (重要メール紛失回避)
要点: FP は単独で良し悪しが決まらない。 「FN とのトレードオフ」「ドメインのコスト構造」「閾値選択」を同時に語ってはじめて意味を持つ。 SSDSE-B のような小標本 (47 県) では FP 1 件で指標が大きく動くため、 信頼区間と併記する。
| 週 | 学習内容 | 演習 | 関連ページ |
|---|---|---|---|
| 1 | 混同行列の 4 セルを定義し、 TP/TN/FP/FN を SSDSE データで計算 | 本ページ Q1-Q3 を解く | 混同行列 |
| 2 | precision / recall / F1 を計算、 不均衡データの落とし穴 | scikit-learn classification_report | 適合率 / 再現率 |
| 3 | ROC 曲線・AUC・PR 曲線を読み解く | RocCurveDisplay で可視化 | ROC 曲線 / AUC |
| 4 | Bayes の定理で PPV を計算、 base rate の支配力を体験 | 本ページ Q4-Q5 | 特異度 |
| 5 | 多重比較補正(Bonferroni / BH 法) | statsmodels multipletests | 多重比較 / FDR |
| 6 | 確率校正と閾値最適化 | CalibratedClassifierCV | ロジスティック回帰 |
| 7 | 公平性指標 (Equalized Odds, Predictive Parity) | サブグループ別 FPR 監査 | 公平性 |
| 8 | ドリフト検知と MLOps での FP モニタリング | PSI / KS / 再キャリブレーション設計 | クラス不均衡 |
偽陽性に強くなる最短の道は、 「検査陽性時の事後オッズ」を即座に概算できるようになることだ。 ベイズの定理を「事前オッズ × 尤度比 = 事後オッズ」の形に書き換えると、 暗算でほぼ正しい PPV が出る。 ここでは 4 つの典型シナリオで実演する。
| シナリオ | 事前確率 | 事前オッズ | LR+ | 事後オッズ | 事後確率 (PPV) |
|---|---|---|---|---|---|
| 無症状一般人 | 0.5% | 0.005:1 | 10 | 0.05:1 | 4.8% |
| 家族歴あり | 5% | 0.053:1 | 10 | 0.53:1 | 34.6% |
| 症状あり | 30% | 0.43:1 | 10 | 4.3:1 | 81.1% |
| 高リスク群 | 50% | 1:1 | 10 | 10:1 | 90.9% |
💡 LR+=10(感度 90% / FPR 9% 程度)の検査でも、 事前確率 0.5% の集団では陽性者の 95% が偽陽性。 同じ検査を症状ありの集団に使えば PPV は 81%。 「検査の精度」よりも「対象集団の選択」が PPV を決める。
| # | 関数 | 用途 |
|---|---|---|
| 01 | RocCurveDisplay.from_predictions | ROC 可視化 |
| 02 | PrecisionRecallDisplay.from_predictions | PR 可視化 |
| 03 | ConfusionMatrixDisplay.from_predictions | 混同行列可視化 |
| 04 | CalibrationDisplay.from_predictions | 校正曲線 |
| 05 | scipy.stats.binomtest(fp, fp+tn, p=0.05) | FPR=5%の検定 |
| 06 | scipy.stats.beta(1+fp,1+tn).interval(0.95) | FPR の 95% CrI |
| 07 | multipletests(pvals, method='fdr_bh') | FDR 制御 |
| 08 | multipletests(pvals, method='holm') | Holm 法 |
| 09 | sklearn.metrics.det_curve | DET 曲線(信号検知) |
| 10 | imblearn.over_sampling.ADASYN | 適応的 SMOTE |
| 11 | fairlearn.metrics.MetricFrame | group-wise metrics |
| 12 | fairlearn.postprocessing.ThresholdOptimizer | 公平性閾値最適化 |
| 13 | evidently.metrics.DataDriftPreset | ドリフト検知 |
| 14 | alibi-detect.cd.KSDrift | KS ドリフト検知 |
| 15 | shap.Explainer(clf)(X[fp_idx]) | FP の SHAP 分析 |
最後に SSDSE-B-2026(都道府県別データ)を用いた実演 5 題で FP の感覚を仕上げる。 ノートブックで pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1]) を実行してから順に解いていく。
confusion_matrix で 4 セル取得 → FPR=FP/(FP+TN), PPV=TP/(TP+FP)。df.groupby('ブロック').apply(...) で各ブロックの FPR を計算、 棒グラフ。roc_auc_score を 1000 回ブートストラップ、 np.percentile で 2.5%-97.5%。CalibratedClassifierCV(method='isotonic', cv=3)。fpr, tpr, thr = roc_curve(y, prob)、 コスト=FP×100万+FN×500万 を計算、 argmin。| # | キーフレーズ | 意味 |
|---|---|---|
| 1 | FP = Type I error | 分類と検定で同じ概念 |
| 2 | specificity = 1 - FPR | 2 指標は補集合 |
| 3 | base rate が PPV を決める | Bayes の本質 |
| 4 | accuracy ≠ 良いモデル | 不均衡で誤導的 |
| 5 | 閾値 0.5 は便宜的 | 業務コストで決める |
| 6 | 校正なき確率は危険 | Platt / Isotonic 必須 |
| 7 | 多重比較は補正必須 | BH 法が標準 |
| 8 | group-wise FPR を見る | 公平性の核心 |
| 9 | 単点推定は弱い | CI / 事後分布で報告 |
| 10 | ドリフトで FPR 変化 | 本番モニタリング |
| 11 | FP コストは業界で異なる | 「許容 FPR」を文脈で |
| 12 | SHAP で FP を分解 | FP 主因の特徴量を発見 |
| 検定の用語 | 機械学習の用語 | 関係 |
|---|---|---|
| 帰無仮説 H₀ | 陰性クラス | 「効果なし/陰性」が初期仮定 |
| 対立仮説 H₁ | 陽性クラス | 「効果あり/陽性」を主張 |
| α (有意水準) | FPR の制約 | Type I error の上限 |
| β (Type II 確率) | FNR | 陽性を見逃す確率 |
| 検出力 (power) | recall / TPR | 1-β に対応 |
| p 値 | 予測確率 | 直接対応はしないが似た役割 |
| FWER | マクロ FPR | 家族全体で誤陽性確率 |
| FDR | 1-precision | 陽性出力中の誤り割合 |
💡 同じ概念に対して統計検定と機械学習で異なる用語が使われるが、 計算式と意味は対応している。 「α=0.05」を設定することは「FPR を 5% 以下に抑える」と同義。 両分野の用語を行き来できるようになると、 ベイズ・頻度論・分類器の議論が一気にクリアになる。
1. FPR = FP / (FP + TN) = 1 - specificity — 陰性のうち誤って陽性とした割合
2. PPV = sens × prior / (sens × prior + (1-spec) × (1-prior)) — Bayes による陽性的中率
3. LR+ = sens / (1-spec) = TPR / FPR — 陽性結果の尤度比
4. 事後オッズ = 事前オッズ × LR+ — 暗算 PPV のショートカット
5. Bonferroni 補正: α' = α / m — m 件の独立検定での補正水準
X[fp_idx] を CSV に出して目視で共通点を探す。💡 この 7 ステップは MLOps チームの「FP インシデント対応 SOP」として使える。 1-2 で「設定問題」を排除し、 3-5 で「データ問題」を疑い、 6-7 で「公平性・ドリフト問題」を確認する流れ。
定義: 偽陽性(False Positive, FP)= 陰性なのに陽性と判定された誤り。 統計検定では Type I error / α エラーと同義。
主要指標: FPR = FP/(FP+TN), specificity = 1-FPR, PPV = TP/(TP+FP), LR+ = TPR/FPR。
Bayes 早見: 事後オッズ = 事前オッズ × LR+。 検査特性が同じでも base rate が低ければ PPV は小さい。
閾値選択: ROC 曲線で目標 FPR を満たす最大 TPR を探す。 業務コスト最小化なら C = c_FP × FP + c_FN × FN を最小化。
多重比較: m 件の検定なら α' = α/m (Bonferroni) または BH 法で FDR 制御。
不均衡対策: class_weight='balanced' → SMOTE → cost-sensitive loss の順で試す。 評価は元分布で。
校正: CalibratedClassifierCV(method='isotonic', cv=5) で確率を物理量に近づける。
公平性: group-wise FPR を必ず報告。 Equalized Odds と業務目的の整合を検証。
本番: PSI / KS でドリフト監視、 月次再校正をルーチン化。
ライブラリ: sklearn.metrics, statsmodels.stats.multitest, imblearn, fairlearn, shap, evidently, alibi-detect。
日本でも偽陽性は医療・金融・公的サービスで議論される。 がん検診では「過剰診断」と呼ばれる FP 関連問題、 マイナンバー関連サービスでは本人確認の FPR が公共議論の対象になった。 自動運転車では歩行者検出の FP は急ブレーキの原因となり、 後続車事故リスクを生むため、 国土交通省のガイドラインで許容 FPR を設けている。 SSDSE-B-2026 の都道府県別データを使った人口減少県判定や、 出生率予測の演習も、 実は政策評価における偽陽性管理と直結しており、 都道府県別 FPR を見比べる思考は政策の説明責任を担保する重要な技法となる。
なお、 偽陽性は単に「数値を下げれば良い」ものではなく、 業務目的・社会的影響・関係者の同意とのバランスで設計する概念である。 本ページの各演習・ケーススタディを通じて、 計算技法だけでなく「FP の意味と扱い方」を文脈で理解できるようになっていれば幸いである。 SSDSE-B-2026 の都道府県データを使った演習をすべて手元で再現すれば、 自分の業務領域に応用するための土台が整う。
本拡張深掘りは SSDSE-B-2026 都道府県データに基づく実演を中心に構成した。 練習問題と図解で「偽陽性をどう減らすか」を実装レベルで把握できるはずである。 関連用語リンクから次の学習トピックへ進んでほしい。
合成データで陰性 1,000 件中の偽陽性件数から FPR を計算する。
| 区分 | 件数 |
|---|---|
| 真陰性 TN | 950 |
| 偽陽性 FP | 50 |
| 合計陰性 | 1,000 |
1 2 3 4 5 | tn, fp = 950, 50 fpr = fp/(fp+tn) spec = tn/(fp+tn) print(f"FPR: {fpr}") print(f"Specificity: {spec}") |
💬 手計算 (Step 2) 0.05/0.95 と Python 出力が完全一致。
「偽陽性」を実際の課題に当てはめるとき、 以下の 3 ステップで判断する。 領域固有の判断基準と組み合わせて使用する。
多重検定では FP が累積するため、 仮説数 m=10 で α=0.05/m=0.005 の Bonferroni 補正、 m=数千で BH 法 (FDR<0.05)、 m=数十万でも Storey の q 値、 と m に応じた補正を選ぶ。 GWAS や fMRI では 10⁵ 以上の同時検定で BH 法が標準。
| 状況 | 第一選択 | 第二選択 | 避ける |
|---|---|---|---|
| スパムフィルタ (FP=正常メール誤判定) | Precision 0.99 + 閾値高め | 2 段階判定 (LLM レビュー) | Recall だけ最適化 |
| 医療スクリーニング (FP=陰性者を陽性) | Specificity 重視、 確定検査を二段 | 感度高め + 二次精査 | Accuracy だけ報告 |
| クレジット不正検知 (FP=正当取引ブロック) | Precision@k + 人手レビュー枠 | cost-sensitive 学習 | 閾値固定 0.5 |
| 少数仮説 (m<20) の同時検定 | Bonferroni (α/m) | Holm-Bonferroni | 無補正 |
| 大量仮説 (GWAS / fMRI m>10³) | BH 法で FDR<0.05 | BY 法 (依存性あり) | Bonferroni (保守的すぎ) |
「偽陽性 (FP, 第 I 種の過誤)」は分類性能評価の出発点であるが、 実務で意味を持たせるには隣接手法と接続・統合・比較の三視点で運用する必要がある。 章 10 が分類体系上の位置づけを示すのに対し、 章 14 は「業務でいつ何に切替えるか」という運用判断の橋渡しを担う。
| 切替先 | FP からこちらへ切替える場面 |
|---|---|
| 偽陰性 (FN) | 癌スクリーニング・侵入検知など「見逃しコスト >> 誤検出コスト」の業務 |
| 適合率 | 陽性予測の「正しさ」をユーザに説明する必要 (スパム判定・推薦) |
| ROC-AUC | 閾値を固定せず全閾値での総合性能でモデル比較したい場面 |
| FDR | 数千件の同時検定 (GWAS / A/B テスト多変量) で Bonferroni が保守的すぎる場面 |
| コスト感応学習 | FP と FN のコストが事前に数値化されており、 損失関数に直接組込みたい場面 |
運用判断は (1) 業務コスト比の数値化 → (2) FN とのペア管理 → (3) 多重検定なら FDR 統合 → (4) 全閾値評価なら AUC 切替、 の 4 軸で整理する。 スパム判定・差止判決・医薬品承認のように False Alarm コストが高い領域では Precision/Specificity を主指標、 癌検診・侵入検知のように見逃しコストが高い領域では FN/Recall を主指標とし、 章 10 (分類体系) と章 14 (運用判断) を併読することで「どの指標を選ぶか」と「いつ切替えるか」の両方を把握できる。
偽陽性は「言葉」で覚えるより「動かして」体感するのが早い。 下の図には 陰性群(本当は無関係・正常な人/県)と 陽性群(本当に該当する人/県)の 2 つの分布が重なって描かれている。 検査は「スコアがしきい値以上なら陽性」と判定する。 スライダー(または図を直接ドラッグ/タップ)でしきい値を左右に動かすと、 偽陽性 FP(陰性なのに陽性判定=陰性分布のうちしきい値の右側)と 偽陰性 FN(陽性なのに陰性判定=陽性分布のうち左側)の領域がリアルタイムに増減する。 しきい値を緩める(左へ)と FP が増え、 締める(右へ)と FN が増える——このトレードオフを指先で確かめてほしい。
陰性群 800 人・陽性群 200 人・標準偏差 12 の正規分布を仮定した教育用モデル(実在データではなく形状理解のための概念図)。 図の縦点線がしきい値。 その右側を陽性と判定する。
しきい値を下げると「少しでも怪しければ陽性」と判定するので見逃し(FN)は減るが、 無実の陰性まで巻き込んで 偽陽性 FP が急増する。 逆に上げると FP は減るが見逃しが増える。 FP と FN を同時にゼロにはできない——2 つの分布が重なっている限り、 一方を減らせば他方が増える。 これが分類・検定の根本的トレードオフである。 上のスライダーで「重なり」を大きく(陽性群の平均を左へ)すると、 どのしきい値でも FP と FN の両方が高止まりすることも体感できる。
しきい値を 10→90 まで全て動かしたときの (FPR, TPR) の軌跡が ROC 曲線 であり、 その曲線下面積が AUC。 FP と FN のコストが非対称なら、 最適しきい値は t* = cFP/(cFP+cFN) で与えられる(コスト感応学習)。 多数の同時検定で偽陽性を統制したい場面では FDR 制御や 多重比較の補正を、 検定の枠組みでは 第一種の過誤と 有意水準の関係を、 判定表の全体像は 混同行列を、 それぞれ併読するとよい。
既存セクションでは偽陽性(False Positive=本当は陰性なのに陽性と判定する誤り/第一種の過誤)の定義・FPR・ROC を扱いました。ここでは重複を避け、「検査そのものは変えていないのに、狙う陽性がまれになるほど適合率(陽性的中率 PPV)が崩壊する」という基準率(base rate)の効き方だけに絞って締めくくります。姉妹ページが扱った「偽陰性の沈黙」「多重比較での誤報増殖」とは別角度です。本節の実測値は公的データ data/raw/SSDSE-B-2026.csv(統計センター)を pd.read_csv(encoding='cp932', skiprows=[1]) で読み、df[df['SSDSE-B-2026']==2023] の 47 都道府県から集計したものです。合成データには「架空」と明記します。
偽陽性の怖さは FPR(陰性を誤って陽性にする率)だけでは伝わりません。実務で問われるのは逆向きの確率、「陽性と判定された中で本当に陽性の割合=適合率 PPV」です。両者は別物で、両者を橋渡しするのが基準率です。狙う陽性がまれだと、陰性の母数が桁違いに大きいため、たとえ 1 件あたりの誤り率が小さくても、湧き出す偽陽性の総数が真陽性を軽く上回ります。「陽性という結果」は「陽性という真実」より、いつも水増しされて出てくる、と身構えるのが正しい直感です。
❌ 「感度(再現率)が高い=陽性判定が信頼できる」という取り違え。 感度と適合率は独立です。下の実データでは、テストが真陽性を 100% 取りこぼさない(再現率 1.00)のに、陽性と判定した県の4 分の 3 は空振り(PPV 0.25)でした。感度をいくら上げても、基準率が低いままなら陽性判定の的中率は上がりません。感度と適合率は必ず両方見ること。
❌ FPR が同じでも、基準率が下がると PPV は下がる。 FPR は「陰性の中での誤り率」なので基準率に不変です。ところが陽性的中率は基準率に強く依存します。同じ検査を回したまま狙う陽性を珍しくしていくと、真陽性(分子)が痩せ、偽陽性(分母の大半)は残るため、検査を一切いじっていないのに PPV だけが崩れます。「テストは変えていないから精度は同じはず」という思い込みが、まれ事象のスクリーニングを失敗させます。
設定(架空の意思決定・数値はすべて実測): 「人が集まる県か」を安く見分けたい。真の陽性=社会増(日本人の転入超過)県と定め、A5101(転入者数)− A5102(転出者数)> 0 で判定すると、2023 年に社会増だったのは 6 県(千葉・埼玉・大阪・東京・神奈川・福岡)=基準率 6/47 = 12.8% というまれな陽性です。
そこへ安価な代理指標「商業地の標準地価 C5403 が全国中央値(81,000 円/㎡)以上なら“集まる県”と判定」というスクリーニングを当てます。すると陽性判定は 24 県、混同行列は次の通り(すべて 2023 年 47 都道府県・skiprows=[1]・in-sample の記述統計)。
| 真:社会増(6県) | 真:社会減(41県) | 計 | |
|---|---|---|---|
| 地価≥中央値と判定 | TP = 6 | FP = 18 | 24 |
| 地価<中央値と判定 | FN = 0 | TN = 23 | 23 |
再現率(感度)= 6/6 = 1.00(真の集まる県を 1 つも逃さない完璧な網)。ところが適合率 PPV = 6/(6+18) = 0.25。陽性と判定した 24 県のうち 18 県は偽陽性(京都・兵庫・北海道・和歌山・奈良・宮城・岐阜・岡山…=地価は高いが社会減)。感度 100% でも、陽性判定の的中は 4 件に 1 件。偽陽性が真陽性の 3 倍湧いています。
決定打は、検査(陽性判定 24 県)を固定したまま、狙う陽性の基準率だけを下げる実測です。真の陽性の定義を「社会増の勢い」で絞り込むと(同じ地価テストを適用):
| 真陽性の定義 | 陽性県数 | 基準率 | TP | FP | PPV |
|---|---|---|---|---|---|
| 転入超過 > 0 | 6 | 0.128 | 6 | 18 | 0.250 |
| 転入超過 > 2万人 | 2 | 0.043 | 2 | 22 | 0.083 |
| 転入超過 > 6万人 | 0 | 0.000 | 0 | 24 | 0.000 |
テストは 1 行も書き換えていない(常に陽性 24 県)のに、基準率が 12.8%→4.3%→0% と痩せるほど PPV は 0.25→0.08→0 へ崩壊し、24 県すべてが偽陽性に振り切れます。これがスクリーニングのパラドックスです。まれな陽性を追うほど、偽陽性が真陽性を圧倒する——検査の良し悪しではなく、母集団の基準率が支配します。実務では、事前に基準率で対象を絞る/二段階検査で確定検査を重ねる、が定石です。
【架空デモ・数式で一般化】 感度 90%・特異度 90% の固定した仮想検査(実データではない架空の想定)を、有病率 p の集団に当てると PPV = (0.9·p) ÷ (0.9·p + 0.1·(1−p))。p=50% なら PPV=0.90 だが、p=1% では PPV≈0.083、p=0.1% では PPV≈0.009。検査は同じでも、まれになるほど「陽性の 99% が偽陽性」に達します。下のスライダーで体感できます。
▶ 架空インタラクティブ:感度・特異度を固定し、有病率(基準率)だけを動かすと PPV がどう崩れるか。バーをドラッグ(マウス/タッチ)または下のスライダーで操作。