scikit.learn手法徹底比較! ナイーブベイズ編

scikit.learnの分類手法を比較するこの企画. 今回はナイーブベイズを検証する.

ナイーブベイズはi番目の入力ベクトルの各次元が, クラスラベルが与えられると互いに独立, すなわち

となると仮定する分類手法である. ただし, の次元数, はi番目の入力ベクトルのj個目の要素を指す.

学習段階では訓練データから各クラスjごとに確率分布を学習し, 分類する際にはが最大になるようなクラスに分類する.

scikit.learnが提供するナイーブベイズのクラスは

  • Gaussian Naive Bayes
  • Bernoulli Naive Bayes
  • Multinomial Naive Bayes

の3つがある.

Gaussian Naive Bayesは分布ガウス分布で表現するクラスである. 訓練データからこのガウス分布のパラメーターを学習する.
Bernoulli Naive Bayesは入力ベクトルの要素が[0,1]の2値を取る場合のナイーブベイズである. 分布はベルヌーイ分布で表現される.
Multinomial Naive Bayesでは, 入力ベクトルの要素がi番目のデータにおいてj個目の要素が何回出現するか(例えば, ある記事において単語soupが何回出現しているか)を表す. なんかテキスト分類とかに使われているらしい.

今回は入力ベクトルとして各次元が画素の値(0-255)なので使えそうなのはGaussianとBernoulliである. Bernoulliの場合はオプションの閾値を設定すると, 入力ベクトルの値が閾値以上の場合は1, 以下なら0として扱う.

なお入力データは正規化している.

Gaussian Naive Bayes

コンストラクタに引数がないシンプルなクラスnaive_bayes.GaussianNBを用いる.

簡単に使えるかと思いきや

/usr/lib/pymodules/python2.7/sklearn/naive_bayes.py:174: RuntimeWarning: divide by zero encountered in log n_ij = - 0.5 * np.sum(np.log(np.pi * self.sigma_[i, :]))

というエラーメッセージが発生し, 真っ当に動作しなかった.

エラーメッセージから察するに, おそらく分散の無い要素(特定のクラスで常に一定の値を取る要素)が存在する場合, 0割りが発生しうまく動作しないのだろう.

そこで, とりあえずの解決策として, 全要素である程度の分散を持つために元のデータにガウス分布から生成したノイズを足しあわせた. その結果正常に動作するようになったが, データ数1万のケースでも分類精度が75%程度でしかもバッドノウハウにも程がある感じだったので, 詳細な検証は取りやめた.

Bernoulli Naive Bayes

調整するパラメーターは次の3つである.

  • fit_prior : 事前分布(クラスごとのデータ数の偏り)を考慮するかどうか
  • alpha : 各次元において1を取る確率に関する事前分布を制御する
  • binarize : 元のデータを2値化するときに用いる閾値

alphaに関しては詳細な説明が必要だろう. alphaを用いることで, クラスcに属するデータのj番目の要素が1となる確率は

と学習される. ここでは学習データにおいてクラスがcである要素の数, は学習データにおいてクラスがcでかつj番目の要素が1となる要素の数である. alphaが小さい程, この確率は純粋なデータ内の比率に近づく.

元のデータのラベル比率が均等に近いためか, fit_priorはTrueにしてもFalseにしてもあまり結果が変わらなかったため, 以下fit_priorはTrueと設定する.

クロスバリデーションによってalphaをnumpy.logspace(-5, 0, 6), binarizeをnp.linspace(-0.2,1.2,6)から選んだ. その選んだパラメーターに対して得られた結果は次の通り.

訓練データ数 正答率 学習時間(sec) 平均予測時間(msec)
1000 0.8134 0.0377149582 0.0484575987
3000 0.8166 0.1247229576 0.0482898951
5000 0.8152 0.221326828 0.0484192133
10000 0.8157 0.4449100494 0.047160697
20000 0.8179 0.919823885 0.0482817888

正答率が見事に上がらないw. やはりモデルの仮定に無理があるためか, 2値化の際の情報の損失が激しいのか. 一方, 学習時間はデータ数に対して線形である. また平均予測時間はデータ数に影響を受けない. これらはアルゴリズムを想像すればまあ納得の行く結果である.

クロスバリデーションをして得た感じとしては, 学習時間は全くパラメーターの影響を受けない. また正答率もalphaなら0から1, binarizeなら0から1という常識的な値から選んでいればそこまで変化しなかった.

まとめ

その性能の低さから「論文で負けるためにある分類器」と言われることもあるナイーブベイズさん. この問題でも性能は低かった. だがテキスト分類など一部の分野では使われており, また学習時間も超短いため, 活躍する領域があるんだろう. ナイーブベイズの仮定がうまく効いてくるデータセットでも試してみたい.