本文へスキップ
ひもとくAI

ミニプロジェクト:ナイーブベイズを自分で作る

レッスン 6/6

ミニプロジェクト:ナイーブベイズを自分で作る

この章で学んだ確率・最尤推定・対数・ベイズの定理を全部使って、レッスン3のナイーブベイズ(GaussianNB)を、ライブラリを使わずに作ります。データは第9章の乳がんの診断データ(30個の特徴量、悪性を0・良性を1)です。

学習:クラスごとに、平均と分散と割合を数える

ナイーブベイズの学習は、勾配降下法を使いません。クラスごとに、次の3つを数えるだけです。

  1. 平均: そのクラスのデータの、特徴量ごとの平均(レッスン4で見たとおり、正規分布の平均の最尤推定)
  2. 分散: そのクラスのデータの、特徴量ごとの分散(これも、正規分布の分散の最尤推定)
  3. 事前確率: 訓練データのうち、そのクラスのデータの割合

訓練データ(398件)で数えると、悪性の事前確率は0.374、良性は0.626でした。例えば「細胞の半径の平均」の特徴量は、悪性のクラスでは平均17.53・分散11.59、良性のクラスでは平均12.19・分散3.04です。

予測:クラスごとに「対数の事後確率」を計算して、大きい方を選ぶ

新しいデータ xx について、クラスごとに、ベイズの定理の分子(事前確率 × 尤度)を計算します。特徴量どうしは関係ないと仮定する(ナイーブ)ので、尤度は特徴量ごとの尤度の掛け算です。30個の小さな数を掛けると小さくなりすぎるので、レッスン4のとおり対数をとって足し算にします。

点数=log⁡(事前確率)+∑特徴量log⁡(その特徴量の、正規分布の尤度)\text{点数} = \log(\text{事前確率}) + \sum_{\text{特徴量}} \log(\text{その特徴量の、正規分布の尤度})

正規分布の尤度の対数は、平均 μ\mu・分散 vv のとき、次の式で計算できます(式の形はレッスン4の「ずれの2乗」と同じです)。

−12log⁡(2πv)−(x−μ)22v-\frac{1}{2} \log (2 \pi v) - \frac{(x - \mu)^2}{2 v}

点数が一番大きいクラスを、予測とします。ベイズの定理の分母は、どのクラスでも同じなので、比べるだけなら計算しなくて済みます。

コードの形

def fit_nb(X, y):
    classes = np.unique(y)                                              # クラスの一覧 → [0, 1]
    means = np.array([X[y == c].mean(axis=0) for c in classes])         # クラスごと・特徴量ごとの平均
    vars_ = np.array([X[y == c].var(axis=0) for c in classes])          # クラスごと・特徴量ごとの分散
    priors = np.array([(y == c).mean() for c in classes])               # 事前確率
    return classes, means, vars_, priors

X[y == c] は、正解が c の行だけを取り出す書き方(第3章の、条件で行を選ぶ方法)です。mean(axis=0) は、縦方向(特徴量ごと)の平均です。

実験の結果と、この章の振り返り

自分で作ったものと、scikit-learn を比べる

前のスライドのとおりに作ったナイーブベイズと、scikit-learn の GaussianNB を、同じテストデータ(171件)で比べました。

正解率scikit-learn と同じ予測だった割合
自分で作ったもの0.9120.977(171件中167件)
scikit-learn の GaussianNB0.924―

同じ方法のはずなのに、4件で予測が違いました。調べると、原因は 分散 でした。

  • 特徴量の中には、「フラクタル次元の標準誤差」のように、値がとても小さく、分散が0.0000033ほどしかないものがある
  • 分散が小さいと、(x−μ)22v\frac{(x - \mu)^2}{2v} の分母が小さくなり、少しのずれでも点数が大きく動く
  • scikit-learn は、計算を安定させるために、すべての分散に「一番大きな特徴量の分散 × 0.000000001」(このデータでは約0.00036)を足している(var_smoothing という設定)

自分で作ったものにも同じ数を足すと、171件すべてで予測が一致し、正解率も0.924になりました。反対に、scikit-learn の var_smoothing を0にすると、自分で作ったものと同じ0.912になりました。

ライブラリには、このような「説明書に小さく書かれた工夫」がたくさん入っています。自分で作って比べると、それに気づくことができます。第9章で学んだように、結果を再現するには、こうした設定も記録しておく必要があります。

この章の振り返り

  1. 確率と期待値: 期待値は「値 × 確率」の合計。大数の法則で、平均は期待値に近づく
  2. 確率分布: ベルヌーイ分布・二項分布・正規分布。中心極限定理。共分散と相関係数
  3. ベイズの定理: 事前確率を、データ(尤度)で事後確率に更新する。条件と結果を入れ替えると別の確率
  4. 最尤推定: データが一番起こりやすくなる値を選ぶ。対数で掛け算を足し算に。MAP推定と正則化
  5. 情報理論: エントロピーは予想しにくさ。交差エントロピー = エントロピー + KLダイバージェンス
  6. ナイーブベイズ: 平均・分散・割合を数え、対数の事後確率で分類する

第5章から使ってきた罰(交差エントロピー)は、最尤推定 から見ても、情報理論 から見ても、同じものにたどり着きます。「なぜこの罰を使うのか」に、数学で答えられるようになりました。

演習

演習を読み込んでいます…