Digital Reactor
機械学習

「精度を上げたい」の前に決めること:精度改善・閾値・運用を経済的インパクトから考える

「精度を上げたい」の前に決めること:精度改善・閾値・運用を経済的インパクトから考える

はじめに

「モデルの精度を上げたい」という相談を受けたとき、私はまず精度の話をしません。先に訊くのは、見逃し1件と誤検知1件でいくら失うのか、判定は月に何件あるのか、いまの閾値は誰がどうやって決めたのか、の3つです。この3つが埋まれば、精度の議論を「どの打ち手で損失がいくら減るか」という経済的インパクトの議論として進められます。モデルの改善も、閾値の引き直しも、運用の変更も、同じ金額の物差しに乗るからです。

与信を模した10万件規模のシミュレーションでは、モデルに一切手を入れず、閾値を誤りのコストに合わせて引き直すだけで期待損失が約24%下がりました。識別力を上げても閾値を放置すれば、効果はその10分の1以下です。改善の予算をモデルに向ける前に、いまの閾値がいくら取りこぼしているかを見たほうがよいという話です。

対象読者:

  • 与信・不正検知・異常検知のモデルを持つ、あるいは導入を検討している事業側の責任者
  • 「精度を上げれば効果が出る」と言われて、その効果額を見積もりたい方
  • 精度指標を事業の損益にどう結びつけるかを整理したいデータサイエンティスト

記事のポイント:

  • 混同行列を期待損失(円)に変換し、閾値・モデル改善・運用変更の経済的インパクトを同じ軸で比べます
  • 最適な閾値は統計指標ではなく誤りのコストで決まることを、閾値スイープで示します
  • 校正されていないスコアでは理論閾値が外れること、コストを±50%動かしても結論が覆らないことを確認します

モデルより先に、誤りのコストと件数を訊く

要になるのは、誤りの方向で損失の大きさが変わることです。見逃し(本来は止めるべき案件を通してしまう、FN)と誤検知(問題ないのに止めてしまう、FP)では、1件あたりの損失がまるで違います。与信なら、貸倒れの数十万円と、優良客を1件逃す期待収益の差は10倍以上開くのが普通で、この比が閾値の置き場所を決めます。あとは判定件数と陽性率です。同じ誤り率でも、件数が2倍なら損失も2倍になります。

残るひとつが現行の運用です。実務でここを掘ると、閾値が「導入時のライブラリの既定値のまま」「前任者が置いた値」で、以来誰も触っていない、という答えがよく返ってきます。閾値をモデルより先に見直す価値がいちばん大きいのは、この状態の現場です。

確認すること無いと決められないこと
見逃し・誤検知の1件あたりのコスト損失を最小にする閾値。コストが無ければ「最適な閾値」は定義できない
判定件数と陽性率改善の効果額。率だけでは金額に直せない
現行の閾値と決まった経緯いまの運用で出ている損失の大きさ。改善の出発点

以前、不正検知のモデルを新しく作りたいという相談を受けたことがあります。話を聞くと、精度そのものより、正常な取引を止めてしまう連絡対応に現場が疲弊していました。コストを分解すると、止める側の負担が見逃しに対して大きく、しかも当時の閾値は低い側に置かれていました。

結局モデルは作らず、閾値をコストに合わせて引き直し、止めた案件を追加確認に回す運用へ変えたところで、当初の目的はほぼ達成できました。受注はしませんでしたが、この判断は今でも正しかったと思っています。金額で並べる見積もりは、作らないほうが得だという結論も出せます。

混同行列を金額に換算する

式は素朴です。予測を4つのマスに分け、それぞれの件数にコストを掛けて足します。

期待損失=FN件数×C見逃し+FP件数×C誤検知  (+  審査固定費)\text{期待損失} = \text{FN件数} \times C_{\text{見逃し}} + \text{FP件数} \times C_{\text{誤検知}} \;(+\; \text{審査固定費})

混同するとすべての符号が逆になるので、正例の向きを先に決めます。以下、正例(y=1y=1)はデフォルト、つまり「貸してはいけない相手」です。 見逃し(FN)はデフォルトを承認して貸倒れになる高コストの誤り、誤検知(FP)は優良客を謝絶して将来の収益を逃す相対的に軽い誤りです。金額に落とせば、前者は与信額に損失率を掛けたもの、後者はその顧客から得られたはずの期待収益になります。ここでは架空値として、見逃し50万円・誤検知5万円(比で10:1)を基本ケースに置き、比較用に見逃し15万円のケース(3:1)も用意します。

def expected_loss(scores, y, thr, c_fn, c_fp, audit=0):
    """閾値 thr で陽性判定したときの総期待損失(円)。"""
    pred_pos = scores >= thr
    fn = int(np.sum((~pred_pos) & (y == 1)))   # 見逃し:デフォルトを承認
    fp = int(np.sum(pred_pos & (y == 0)))       # 誤検知:優良客を謝絶
    n_audit = int(np.sum(pred_pos))             # 止めた件数(追加審査に回す)
    return fn * c_fn + fp * c_fp + n_audit * audit

同じAUCでも、閾値で損益が変わる

再現できるよう、データは生成します。20万件、陽性率3%、潜在的な信用力からデフォルト確率を引き、観測できる特徴量に測定ノイズを乗せます。このノイズの大きさで識別力を操作でき、あとでAUCを変えた比較に使います。スコアはロジスティック回帰で、基本モデルのAUCは0.854でした。数字はすべて架空値で、実在の案件のものは使っていません。

評価には手当てをひとつ入れてあります。閾値を選ぶデータと、その閾値の損失を評価するデータは分けます。 同じデータで損失最小の閾値を選んでそのまま損失を報告すると、たまたまそのデータに合った値を選んでいるぶんだけ、効果を楽観的に見積もってしまいます。

そのうえで、モデルを固定したまま閾値だけを動かします。

閾値スイープの期待損失曲線。損失最小はスコア0.078付近にあり、統計指標で選んだYouden最大(0.028)はそこから大きく外れて損失を約4割増やす。

曲線は深いU字を描きます。閾値を下げすぎれば誰でも止めてしまい誤検知が積み上がり、上げすぎればデフォルトを次々に見逃します。損失が最小になるのはスコア0.078付近でした。統計指標で選んだ閾値はここから外れます。感度と特異度のバランスを取るYouden指数の最大点は0.028で、損失は最小より4割ほど高くなりました。F1最大点はたまたま近くに来ましたが、それはコスト比が10:1のときの偶然です。

ずれるのは、Youden指数やF1が金額をまったく見ていないからです。見逃しと誤検知を対等に扱うか、あるいは決まった重みで扱うだけで、「見逃しは誤検知の10倍高い」という情報が入っていません。

誤りのコスト比を10:1から3:1に変えると、損失を最小にする閾値が0.078から0.216へ動く。閾値は統計ではなくコストで決まる。

見逃しが相対的に軽くなる(3:1)と、無理に止める必要が薄れ、最適な閾値は0.078から0.216へ上がりました。同じモデル・同じデータでも、誤りのコストが違えば止めるべきラインは別の場所にあります。閾値は統計指標ではなく誤りのコストで決まり、コストを決めないかぎり「最適な閾値」は定義できません。

理論閾値が効くのは、確率が校正されているときだけ

コストから閾値を直接引く近道があります。損失を微分すると、最適な閾値はおおよそ

tC誤検知C見逃し+C誤検知t^{*} \approx \frac{C_{\text{誤検知}}}{C_{\text{見逃し}} + C_{\text{誤検知}}}

に対応します。10:1なら 5/(50+5)0.0915/(50+5) \approx 0.091 です。ただしこの式が成り立つのは、スコアが確率として校正されているとき、つまり「0.1と出た集団の実際のデフォルト率がおよそ10%」であるときに限られます。

信頼度曲線。校正前の生スコアは高確率側で対角線から外れるが、isotonic回帰で校正すると全域で対角線に近づく。

実際、生のロジスティック回帰スコアで損失最小になる閾値は0.078で、理論値の0.091から離れていました。信頼度曲線を見ると、確率が高い領域で対角線から外れています。isotonic回帰で校正してから同じ計算をすると、損失最小は0.088となり、理論値にほぼ重なりました。コストから閾値を引く前に、信頼度曲線1枚でスコアが確率になっているかを確かめておきます。この手順を省くと、正しいコストを入れても閾値を外します。校正の手法は確率校正の入門記事で扱っています。

AUCを0.02上げると、いくら得をするのか

今度は閾値を毎回最適に選び直したうえで、モデルのAUCを段階的に変えます。

AUCと最適閾値での期待損失。AUCが上がると損失は下がるが、+0.02が生む金額はこの設定で数千万円規模にとどまる。

AUCが上がれば損失は下がります。ただし効き方は問題の設定しだいで、ここではAUCを0.02上げても損失の減りは3千万円台にとどまりました。少なくないとはいえ、閾値の置き方で動く額とは桁が違います。

そこで、出発点を「現行は慣習の閾値0.5のまま」として、3つの施策を同じ金額で並べます。0.5は多くのライブラリの既定値ですが、陽性率3%のデータでは高すぎて、デフォルトのほとんどを見逃します。

施策AUC閾値期待損失現行比
現行運用0.8540.5(慣習)704百万円
a) モデルをAUC+0.02改善(閾値は0.5のまま)0.8720.5691百万円−2%
b) モデルは触らず、閾値をコストに合わせて引き直す0.8540.078537百万円−24%
c) 誤検知1件のコストを半減(追加確認に回す)+閾値最適化0.8540.045412百万円−41%
(参考)a) に加えて閾値も最適化0.8720.091509百万円−28%

モデルを改善しても閾値を放置すれば、効果は2%どまりです。改善した精度が、高すぎる閾値でせき止められて損益に届かないからです。モデルに触れず閾値を引き直すだけなら24%減り、運用側で誤検知1件のコストを下げてから閾値をさらに下げると41%です。モデル改善に閾値最適化まで足した参考行(−28%)も、閾値だけを直したb(−24%)をわずかに上回るにすぎません。この現場で損失を支配しているのは、閾値と運用の設計です。モデルの精度はその次に来ます。

ただし、この結論はコストの値に頼っています。見逃し1件のコストは1つの数字に決めきれないので、±50%動かして施策の大小が入れ替わるかを確かめます。

感度分析。見逃し1件のコストを±50%動かしても、どのシナリオでも閾値の引き直し(b)がモデル改善(a)を下回り、結論は覆らない。

低め・中央・高めのどこに置いても、閾値を引き直したほうが損失は小さいままでした。結論が細部で覆らないなら、いま手元にあるおおよその見積もりで意思決定してよいと判断できます。覆るようなら、先にコストを精査してから決める、という順番になります。

この見積もりが外れるとき

最適な閾値は、入力や出力の分布が変われば古くなります。景気や季節で申込者の顔ぶれが動けば、去年引いた閾値は今年の最小ではありません。閾値は一度引いたら終わりにせず、分布の変化を監視して引き直す運用とセットにします。ずれをどう検知して回すかは、小規模チームのMLOps最小構成で扱っています。スコアの校正も、同じ理由で時間とともにずれます。

コストの決め方にも注意が要ります。KPIから逆算すると営業と審査で違う数字が出てくるのが普通で、どの値で最適化するかは合意の場を先に作る必要があります。追加審査に回せるのが1日◯件までと決まっている現場なら、止める件数が先に固定されるので、最適化の変数は閾値から「スコア上位k件をどう選ぶか」に変わります。また、期待損失はあくまで平均の値です。まれに起きる巨額の貸倒れが裾にどれだけ潜むかは、テールリスクの記事の観点で別に見ます。

まとめ

精度改善は打ち手のひとつにすぎません。閾値の設計も運用の変更も、同じ金額に換算しなければ優劣を比べられません。今回のシミュレーションでは、モデルに手を入れず閾値を引き直すだけで期待損失が約24%下がり、AUCを0.02上げて閾値を放置した場合の2%を大きく上回りました。相談の入口で、精度より先にコストと件数を訊くのは、このためです。

もっとも、この枠組みが使えない領域もあります。安全や法令が判定を縛っていて、見逃し1件を金額で言い切れない場合です。コストが原理的に決めにくいなら、期待損失の最小化より先に、満たすべき制約を明文化するほうが実務に合います。逆に、コストのおおよその見積もりと件数、現行の閾値が言えるなら、手元のスコアを一度校正し、そこから閾値を引き直して、いまの運用がいくら取りこぼしているかを金額で出してみてください。改善予算をモデルに向けるべきかどうかは、その数字を見れば決まります。

関連記事

← 技術ブログ一覧へ