前置き
二値分類モデルの学習ではLightGBM一択な今日この頃。ですが、そこで吐き出されるスコアは必ずしも確率値を示していないと常々悩んでおりました。これを何とかしたいと色々試行錯誤していたらそれなりに良さそうなやり方を思いつきました。
二値分類とは
二値分類とはゼロかイチかを当てる機械学習のタスクです。用語としては正か負かという言い方のほうが機械学習っぽいかと思うので以下ではそうやって書きます。
よくあるのが病気の診断で、検査結果から受診者が罹患しているか(正)、罹患していないか(負)を判定する、という類のタスクです。二値分類モデルに受診者の性別年齢と各種検査を投入すると、その人が罹患している可能性をスコアとして出してくれるというのがモデルに求められる機能ですが、正か負かと二つに一つで判断するためには適当な閾値でスコアを区切る必要があります。スコアの順番に並べて適当な閾値で区切ればよいので、「罹患している可能性」は確率値でなくてもよいわけです。
しかし、「罹患している可能性」の高低でなくて、ずばり確率値で欲しい場合もあります。例えば、サービスAとサービスBがあったときに、ユーザに片方だけを訴求するなどちらがよいかといった場合です。これも二値分類の応用となりますが、加入確率の高いものを訴求、となるとA、Bそれぞれの二値分類スコアが比較可能でなくてはなりません。つまり、スケールやバイアスが同じである必要があるということです。
予測値の分布
LightGBMによる学習
kaggleからsantanderのデータをLightGBMに放り込んでモデルを作りました。これは金融商品の購入をするか否かのデータセットで、正例割合が10%と程よく不均衡です。目的変数は1か0ですが、書きやすさのため1を正、0を負と書きます。
パラメータはこんな感じ。不均衡なデータだとis_unbalanceを入れておくと、正負が半々になるようにサンプリングして学習するので予測値が適度に広がります。
パラメータ | 値 |
---|---|
objective | binary |
num_leaves | 15 |
is_unbalane | True |
num_boost_round | 100 |
スコアと正例割合
データ点ごとのスコアを0.01刻みにまとめて正例の割合をとってみます。そうするとスコアと正例割合の相関図を描くことができます。ちなみに、rmseは対角線からの誤差です。
これが(0,0), (1,1)の対角線と重なると、予想値がそのまま正例割合を予測することになって、応用的にはいろいろとうれしいわけです。
スコアの分布
正負別々に分布をみてみるとこんな感じ。
正例と負例が重なる予測値の範囲では正例割合が0
から1になります。重ならない範囲では負例のみであれば正例割合は0、正例のみの分布であれば正例割合は1になります。そんなわけで上のようなシグモイドっぽい相関図になるわけです。
ベータ分布
ところでこの形、ベータ分布にそっくりです。形もベータ分布っぽいなら確率変数が0から1だということもベータ分布と同じです。というわけで、平均と分散からalpha, betaを求めましょう。
e = \frac{a}{a+b}
v = \frac{ab}{ (a+b)^2 (a+b+1)}
これを解いてやると、
a = \frac{e^2 (1-e)}{v}-e
b = \frac{(1-e)}{e}a
上記パラメータでベータ分布のランダムサンプリングを描くとこんな感じ。
0.1や0.9近辺では少し形が違いますが、まあいいでしょう。
正例割合の予測
正負それぞれのalpha, betaがあれば後は0から1の任意の確率変数から正負それぞれの確率密度が計算できます。さらに、元のデータの正負の数があれば、任意の確率変数での正負の割合が計算できます。
Y = \frac{N_p\times Beta_p}{N_p\times Beta_p + N_n\times Beta_n}
LightGBMからの元々の予測値に対して、べーて分布からの予測値をプロットするとこんな感じ。
さらにベータ分布からの予測値と先ほどの正例割合との相関図はこんな感じ。
対角線にかなり近づいていることがわかります。
というわけで、LightGBMとベータ分布の二段構えで、予測値と正例割合を対角線上に近づけることができました。
まとめ
- 二値分類モデルから出てくるスコアは正例割合とプロットしたときに対角線に乗らないことが多い。
- スコアを適当なパラメトリックな分布にフィッティングできればスコアから正例割合を計算できる。
あとがき
3/1に技術書典8で本を出す予定でしたが、例のウィルスのおかげで中止となってしまいました。