Naive Bayesの罠

< Naive Bayesの実装 < | > ---- >

================================================

Naive Bayes(NB,ナイーブベイズ)には気になる事があるよ、という話。前回、文書{バナナ,カレー}が「甘い」クラスと「辛い」クラスそれぞれに属する確率(対数尤度)をナイーブベイズ分類器で求めた。

その結果、文書{バナナ,カレー}は「辛い」クラスに属することがわかった。しかしバナナもカレーも「甘い」クラスに入っているのに「辛い」クラスのほうが対数尤度が大きいというのはちょっと直感に反するかもしれない。以下ではこの点について考察する。


前回求めた対数尤度の計算式は以下の通り。

lnP(甘い|{バナナ,カレー})
= lnP(カレー|甘い) + lnP(バナナ|甘い) + lnP(甘い)
= 0.69 + 0.69 - (2 - 1) * 2.64 + Const
lnP(辛い|{バナナ,カレー})
= lnP(カレー|辛い) + lnP(バナナ|辛い) + lnP(辛い)
= 1.1 + 0 - (2 - 1) * 2.2 + Const

これはまとめると

lnP(Ci|D)
 = Σj{ln count(wj|Ci)} - (|D| - 1) * ln{Σj count(wj|Ci)} + Const

という計算をしていることになる。ここで注目したいのは第2項。ln{Σj count(wj|Ci)}はクラスCiの総単語数でこれに文書サイズ|D|をかけたものがスコアから減算される。つまり最初に用意したデータ集合中にCiクラスのデータが多いほど減算される量が大きくなってスコアが下がる。しかも入力文書が大きければ大きいほどそれは顕著になる、ということ。つまり、最初に述べた「辛い」クラスの方がスコアが大きい、というのは「辛い」クラスのほうがデータ点が少ないから、ということに起因している。

何故こういう問題が起きるのかというと、NBの確率計算に最尤推定を用いているから。最尤推定ではデータ集合が世界のすべてなので例えばクラス「辛い」のデータが2個しかなくて、そのうち単語「カレー」が出てくるのが1回。というのと、クラス「辛い」のデータが1000個あって、そのうち単語「カレー」が出てくるのが500回。というのが同じに扱われてしまう。つまりデータ点の少ないクラスでは、たまたまサンプルに出てきただけかもしれない単語が非常に大きく扱われてしまう。

この問題は、データ集合をスムージングして本来の分布に近づけることで解消できる。実は、前回述べたゼロ頻度問題解決のために単語に1ずつ頻度を足したのも、ラプラス・スムージングというスムージング手法のひとつ。

最近ではベイズ的なアプローチでスムージングをするのが流行っていて、これは尤度関数に適切な事前分布を設定してあげることで実現できる。

他にも、Complemental Naive Bayesという方法があるが、これはtkng先生がわかりやすく解説してくださっているので、そちらに譲る。
http://d.hatena.ne.jp/tkng/20081217

もっとも超大規模なデータが使える場合には(つまりクラス間のサンプル数に偏りがなければ)スムージングはゼロ頻度さえ回避できればよく、そんなに神経質にならなくて大丈夫。実際GoogleではStupid-Backoffという単純な手法が取られているそうな。
Large Language Models in Machine Translation

というわけで、ナイーブベイズというと簡単だという印象があるけれど実は色々考えることがあるよ、という話。

================================================< Naive Bayesの実装 < | > ---- >