yardstickパッケージでモデル性能を多角的に評価。回帰・分類問題の主要指標からカスタムメトリックまで、実用的な評価手法を完全身につける。
退職予測モデルを組んで、最初にロジスティック回帰を走らせたときの精度が92%でした。 いいモデルができたと思いました。冷静に考えると、その会社の年間退職率は約8%です。 つまり全員に「辞めない」と答えるだけで、自動的に92%になる。モデルは何も学習していないのと同じでした。
この章はyardstickの関数カタログではありません。不均衡なデータで、何を見て、どこで判断を止めるかを書きます。 退職予測は人事データで最も事故が起きやすい題材なので、それを例に進めます。
Accuracyだけ眺めていると見えないものが、混合行列を出すと即座に見えます。私の場合はこうでした。
退職者80人を、ひとりも捕まえていませんでした。Accuracyは92%です。 この2つの数字が同居できてしまうのが、クラス不均衡のある分類問題です。
yardstickは因子の第1水準を陽性(イベント)として扱います。
退職を「1」、在職を「0」としたまま factor() に通すと、水準はアルファベット順で 0, 1 になり、
在職のほうが陽性として計算されます。RecallもPrecisionも、意図と逆の数字が返ります。
水準の順番を明示するか、event_level = "second" を渡してください。ここを間違えたまま
「Recallが高いモデルができた」と報告すると、後で全部やり直しになります。
ROC曲線は陰性クラスが圧倒的に多いと楽観的に見えます。退職率8%のようなデータでは、
pr_curve() / pr_auc() を併せて確認してください。
autoplot() にそのまま渡せます。
指標選びに一般解はありません。どちらの間違いが高くつくかで決まります。 退職予測でいちばん避けたいのは見逃しです。辞める人を「大丈夫」と判断してしまうと、打つ手がなくなります。 逆に「リスクあり」と出した人が辞めなかった場合のコストは、面談を1回多くやることです。
コストが非対称なので、主軸は Recall(退職者のうち何割を事前に捉えられたか)になります。 Accuracyは、この場面では見なくていい数字です。報告資料から外しました。
モデルが出すのは0〜1の確率です。どこで線を引くかは分析者が決めます。 デフォルトの0.5を下げればRecallは上がりますが、上げすぎると全員が「リスクあり」になります。 Recall 100%のモデルは作れます。使えないだけです。
ここで効いたのは、統計的な最適化ではありませんでした。 「何人までなら対応できるか」を先に人事チームと決めて、そこから閾値を逆算するやり方です。 月に20人まで面談を積めるなら、アラートが20人に収まる閾値を選ぶ。それだけです。
なので閾値を振るときは、RecallとPrecisionだけでなくアラート件数を必ず列に入れます。 この列がないと会話が始まりません。
probably パッケージの threshold_perf() を使えば、この掃引を1行で書けます。
ただ自分で書いたほうがアラート件数のような独自の列を足しやすいので、最初は手で組むのをおすすめします。
ここは技術的な判断ではなく運用の判断です。「Youden's J で最適」と言って持っていっても、 現場が回らなければ使われません。掃引した表を持って行き、対応可能な人数を先に聞く。 そこから閾値が決まります。順番が逆になると、たいてい形骸化します。
クラス不均衡への対処というと、SMOTEなどのオーバーサンプリングや、学習時の重み調整が挙がります。 どちらも有効ですが、私は最初の一手として閾値の見直しを選びました。理由は精度ではなく、説明のしやすさです。
「少数クラスの合成データを生成して学習データを水増ししました」と人事チームに説明するのと、 「70%以上をリスクありと呼んでいたのを、55%以上に変えました」と説明するのでは、後者のほうが伝わります。 データを触らずに運用側のつまみだけで調整できる、という点も扱いやすい。
それでも足りない場合に、学習側で重みをかけます。tidymodelsなら
step_downsample() / step_upsample()(themis)をレシピに入れるか、
LightGBMなら scale_pos_weight を設定します。
実際に一度過学習させました。データ量が小さいのに num_leaves を大きくしすぎたのが原因です。
葉あたりの最小データ数を増やして正則化をかけたら落ち着きました。
人事データは行数が数千のオーダーになりがちなので、木を深くする方向のチューニングは効きにくいと思っておいたほうがいいです。
変数を入れ替え、閾値を調整したあとの数字がこうなりました。
冒頭のAccuracy 92%と、このAUC 0.92は数字として近いのに、意味がまったく違います。 前者は何も予測していない状態で、後者は退職者の8割を事前に拾えている状態です。 報告するときは、この違いを先に説明したほうがいい。数字だけ出すと同じに見えます。
Precision 0.61 は「4割は空振り」ということでもあります。これを低いと見るかは運用次第です。 面談を1回多くやるだけのコストなら、見逃しを減らすほうを取る。そういう判断ができるように、 Precisionはアラート件数と一緒に提示します。
指標を整えて、閾値を決めて、リストが出ました。この時点でぶつかったのが「で、この人をどうするのか」です。 第22章でサーベイの自由記述について書いたことと、構造はまったく同じでした。 出力はできる。次の一手に繋がらない。
いくつか分かったことがあります。退職を申し出てきた時点では、たいてい転職先が決まっていて手遅れです。 意味があるのは、まだ迷っている段階で声がかかることでした。スコアが教えてくれるのは 「誰が辞めるか」ではなく「いつ声をかけるか」です。
もうひとつ、スコアの届け方も設計が要りました。マネージャーに「Aさんは退職確率73%です」と伝えるのは、 本人との関係に影響します。スコアは人事が持ったまま、「このメンバーと近いうちに1on1の機会を作ってください」 という形に変換して渡す。この一段階を挟むかどうかで、運用の受け入れられ方が変わりました。
この章は評価指標に絞って書きました。実際にどの変数が効いてどれが効かなかったか—— 残業時間が効かなかった理由、評価の絶対値ではなく差分を使う話、 エンゲージメントサーベイの回答スタイルバイアスをどう除去したか、 ロジスティック回帰からLightGBMに移した判断基準まで含めた全過程は、noteに別途まとめています。
【実務公開】退職予測モデルを作ったら最初に「罠」に落ちた話|ES差分×LightGBMで精度92%に至るまで(有料記事)
リストが出たあとに必ず聞かれるのが「なぜこの人がリスク高と出たのか」です。 予測の根拠を説明できないモデルは、人事の現場では使われません。 変数重要度とSHAPをどう扱うかは第19章で書きます。
※ 当サイトはAmazonアソシエイトプログラムに参加しています