確率予測とCalibrationについて

概要

確率予測とCalibration(キャリブレーション)に関する勉強会に参加したので、学んだことの一部と、自分で調べてみたことについてまとめました。

techplay.jp

勉強会で使われていた言葉を、自分なりの言い方に変えています。
間違いがありましたら、コメントいただけたら嬉しいです。

Calibrationとは

普通の分類問題では、どのクラスに属するかを判別するモデルを作りますが、あるクラスに属する確率はどのくらいか、を予測したい場合を考えます。( 降水確率や広告のCTRなどを予測したい場合など )

モデルの出力値を各クラスに属する確率に近づけること ( モデルの出力値を正解ラベルのクラス分布に近づけるということ ) を、Calibration(較正)と言いいます。

イメージ

モデルの出力値 正解ラベル Calibrationした値
0.4
1
0.5
0.4
0
0.5
0.9
1
1.0
0.9
1
1.0

この記事では、確率予測という言葉を、そのクラスに属する確率の予測という意味で使います。

Calibration Curve

Calibration Curveは、確率予測の信頼性を可視化したものです。
作り方は、データを予測値でビニングし、ビニングしたデータの予測値の平均と、それに対応するPositiveデータの出現率でプロットします。

以下の図はCalibration Curveを使い、各モデルの出力値が、確率予測としてどれくらい良いかを表しています。

f:id:YukoIshizaki:20200523134440p:plain:w670

黒い点線に近いほど、確率予測として信頼度が高いと言えます。ただし、ビン数やどのようにビニングするか(値で区切るか、個数で区切るか)でグラフが変わってしまうことに注意です。

Calibrationの方法

Calibrationの方法を2つ記載します。

Sigmoid / Platt Scale

説明変数をモデル出力値 f(x)、目的変数を正解ラベルとしてSigmoid関数にフィットさせ、そのSigmoid関数に通した値をCalibrationした値とします。

 P(y=1|x) = \displaystyle \frac{1}{1+\exp^{Af(x)+B}}

上記式における ABは勾配降下法などで求めます。

 argmin_{A,B} \bigl\{ - \displaystyle \sum_i{y_i} \log(p_i) + (1-y) \log(1-i_i)  \bigr\}

scikit-learnのSigmoid Calibration実装
https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/calibration.py#L392

この方法は、Calibration CurveがS字になるようなものに有効で、scikit-learnには線形SVMの例が記載されていました。

f:id:YukoIshizaki:20200523122129p:plain:w530

SVMはマージンを最大化して境界部分を厳しく判別するというモデルの性質から、予測値が 0.5 付近に集中します。それを改善するためにSigmoid関数にフィットさせて0.5 付近を平すというのは直感的にもわかりやすいです。

f:id:YukoIshizaki:20200523125649p:plain:w460

Isotonic Regression

ノンパラメトリックな手法として、Isotonic Regressionがあります。
Isotonic Regressionは、Isotonic関数  m (単調増加)を使い以下のように表せます。

 y_i = m(f(x_i)) + \epsilon_i

Isotonic Regressionのアプローチの1つにPAV (pair-adjacent violators) という方法があります。
データを予測値でソートし、隣接ペアで予測値と正解ラベルとの順序関係を保つように、調整された値を計算していく方法です。

f:id:YukoIshizaki:20200523163153p:plain:w430
https://www.cs.cornell.edu/~alexn/papers/calibration.icml05.crc.rev3.pdf

PAVは計算量が  O(n^2) となるため、scikit-leranの実装では、Active set algorithms for isotonic regression; A unifying frameworkに記載されている計算量が  O(n) の方法で、Isotonic Regressionを実装しているようです。
link.springer.com

scikit-leranの Isotonic Regression 実装部分
https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/isotonic.py#L134

Naive Bayes を Isotonic Regression で Calibrationした例がscikit-leranに記載されてました。
f:id:YukoIshizaki:20200523141520p:plain:w600

確率予測に使われる評価指標

確率予測でよく使われる指標を調べてみました。

Brier Score

確率予測した値とラベル(0,1)との二乗誤差の平均。MSEと式は同じ。

 BS =\displaystyle \frac{1}{n} \displaystyle \sum_{t=1}^{N} ( {f_t - o_t} )^2

  •  f_t : 予測された確率
  •  o_t : 実際に起こったか (  \in \{0, 1\})

Brier score - Wikipedia

ECE

データをビニングして、そのビン内での精度と信頼度の差を加重平均したもの。予測クラスと確率予測値の両方が必要。

 ECE = \displaystyle \sum_{b=1}^{B}  \displaystyle \frac{n_b}{N} | {acc(b) - conf(b)} |

  •  B : ビン数
  •  N : 全体のサンプル数
  •  n_b : ビン内のサンプル数
  •  acc : accuracy ( 精度 )
  •  conf : 確率予測値の平均( 信頼度 )

https://openreview.net/pdf?id=r1la7krKPS

コード

scikit-learnに CalibratedClassifierCV があり、引数 method に "sigmoid" か "isotonic" を指定しすることで scikit-learn 準拠モデルで使用できます。
引数 cv に "prefit" を指定すると、すでにbase_estimatorが適応されているモデルとみなされます。

from sklearn.calibration import CalibratedClassifierCV, calibration_curve
from sklearn.svm import LinearSVC
from sklearn.metrics import brier_score_loss
import plotly.graph_objects as go

clf = LinearSVC()
cl_clf = CalibratedClassifierCV(clf, cv=3, method='sigmoid') 
cl_clf.fit(X_train, y_train)

# calibracationされた値を取得
prob_pos = cl_clf.predict_proba(X_test)[:, 1]

# 評価
clf_score = brier_score_loss(y_test, prob_pos)
print("Brier Score: %1.3f" % clf_score)

# calibration curve
fraction_of_positives, mean_predicted_value = calibration_curve(y_test, prob_pos, n_bins=10)

fig = go.Figure(data=go.Scatter(x=mean_predicted_value, y=fraction_of_positives))
fig.show()

不均衡データに対するCalibration

不均衡データをUndersamplingした場合、サンプル選択バイアスが生じ、少数派クラスの確率が大きくなってしまいます。なのでCalibrationして、バイアスを除去します。

この場合のCalibrationは上記に記載したような Sigmoid や Isotonic Regression を使った方法ではなく、以下のような式を使います。

 p = \displaystyle \frac{\beta p_s}{\beta p_s + p_s + 1}

  •  p_s: Undersamplingして学習した時の予測値
  • \beta: Undersampling率を \beta とします。

実際の例がこちらのブログに記載されていました。
pompom168.hatenablog.com
https://www3.nd.edu/~dial/publications/dalpozzolo2015calibrating.pdf

追記
こちらに関して、発表者の方からコメントを頂いております。合わせて確認いただけたらと思います。

LightGBMにCalibrationは不要か

上記にSVMやNaive Bayesの例を記載しましたが、LightGBMに関してはどうなのでしょうか。

ちなみに、同じ木系でもRandom Forestの場合は、バギングというアンサンブルの性質から予測値が 0, 1 付近ではなく、それより少し離れたところに多く集中してしまうため、Calibrationが必要です。(バギングで限りなく 0 付近、限りなく 1 付近の予測値を出すには、各木がほとんど間違えずに予測する必要があるため)

Random Forestの予測値分布
f:id:YukoIshizaki:20200523203432p:plain:w300

しかし、LightGBMはブースティングなのでこれとは異なり、Log Lossを最適化することでcalibrateされるとの考察をいくつか見つけました。(それでモデルが自信過剰・自信不足になっていないと言えるのか、私には確信が持てなかったので詳しい人がいたらコメントいただけたら嬉しいです...)

追記
こちらに関しても、発表者の方からコメントを頂いております。合わせて確認いただけたらと思います。

NNにCalibrationは不要か

同じように、NNではどうなのか?という疑問ですが、こちらの論文を見つけました。
この論文では、最近のNNは自信過剰 (0, 1に近い) で、Calibration が不十分であると記載されていました。

http://proceedings.mlr.press/v80/kumar18a/kumar18a.pdf

追記 : Calibrationの検討について

ブログを公開したところ、ありがたいことに以下のようなツイートをしていただけました!
確かに、train, val, test のそれぞれの予測値/目的変数の平均と分布を見て、Calibrationの必要性を総合的に判断するのが良さそうです。

追記 : 発表スライドについて

勉強会で発表された資料が後日公開されたので、紹介いたします。
冒頭でも記載したとおり、本ブログは、こちらの発表内容の一部と、そのあと自分で調べた内容を記載したものです。以下の資料はCalibrationに関してより詳しい説明が記載されている資料となります!合わせてご確認いただけたらと思います。

speakerdeck.com
Pythonサプリ プログラミング学習

終わり

勉強会では分類全般における評価指標の比較についても言及されていて、とても面白かったので、またそのあたりについても記事を書きたいです。

オンラインで色々な勉強会に気軽に参加できるのは、引きこもり生活の中で非常にありがたいと感じました。