ミニプロジェクト:ナイーブベイズを自分で作る
この章で学んだ確率・最尤推定・対数・ベイズの定理を全部使って、レッスン3のナイーブベイズ(GaussianNB)を、ライブラリを使わずに作ります。データは第9章の乳がんの診断データ(30個の特徴量、悪性を0・良性を1)です。
学習:クラスごとに、平均と分散と割合を数える
ナイーブベイズの学習は、勾配降下法を使いません。クラスごとに、次の3つを数えるだけです。
- 平均: そのクラスのデータの、特徴量ごとの平均(レッスン4で見たとおり、正規分布の平均の最尤推定)
- 分散: そのクラスのデータの、特徴量ごとの分散(これも、正規分布の分散の最尤推定)
- 事前確率: 訓練データのうち、そのクラスのデータの割合
訓練データ(398件)で数えると、悪性の事前確率は0.374、良性は0.626でした。例えば「細胞の半径の平均」の特徴量は、悪性のクラスでは平均17.53・分散11.59、良性のクラスでは平均12.19・分散3.04です。
予測:クラスごとに「対数の事後確率」を計算して、大きい方を選ぶ
新しいデータ について、クラスごとに、ベイズの定理の分子(事前確率 × 尤度)を計算します。特徴量どうしは関係ないと仮定する(ナイーブ)ので、尤度は特徴量ごとの尤度の掛け算です。30個の小さな数を掛けると小さくなりすぎるので、レッスン4のとおり対数をとって足し算にします。
正規分布の尤度の対数は、平均 ・分散 のとき、次の式で計算できます(式の形はレッスン4の「ずれの2乗」と同じです)。
点数が一番大きいクラスを、予測とします。ベイズの定理の分母は、どのクラスでも同じなので、比べるだけなら計算しなくて済みます。
コードの形
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) は、縦方向(特徴量ごと)の平均です。