機械学習初心者がナイーブベイズに手を出してみる (1) - 理論編

## このページ

機械学習初心者、Python初心者なので基本的に参考にさせていただいたページを読み解く感じになると思います。

## 条件付き確率(ベイズの定理)って？？

少し、数学の話です。 `条件付き確率` という言葉を聞いたことはありますか？
前に授業で少し聞いたくらいでほぼ覚えていませんでした。

```math
P(B|A) = \frac{P(A \cap B)}{P(A)} = \frac{P(B)P(A|B)}{P(A)}
```

`P(B|A)` というのは、事象Aが起こった場合の事象Bが起こる確率を言います。

有名な問題に、子供の話があります。

> ある夫婦には子供が二人いる。二人のうち少なくとも一人は男の子であるということが分かった。このとき，二人とも男の子である確率を求めよ。ただし，男の子が生まれる確率，女の子が生まれる確率はともに 1/2 とする

これの考え方は

* 事象A : `二人のうち少なくとも一人は男の子であるということが分かった。`
* 事象B : `二人とも男の子である`

と考えれば、以下のように考えることができます。

### 事象A

`少なくとも一人は男の子` と言っているわけですから、2人子供が生まれる場合の全パターンを列挙すると `男&男`, `男&女`, `女&女`, `女&男` の4パターンです。 (兄弟の違いも含めています)  
そのうち、どちらも `女` である `女&女` を省いた `3/4` が事象Aの確率になります。

### 事象B

これは、言わずもがな`1/4` ですね。

つまり、 P(B|A) の確率は

```math
P(B|A) = \frac{\frac{1}{4}}{\frac{3}{4}} = \frac{1}{3}
```

となります。

参考 : [高校数学の美しい物語](http://mathtrain.jp/bayes)

## ナイーブベイズに挑戦

さて、本題です。ナイーブベイズとは単純ベイズとも言います。
先ほどのベイズの定理を少し変形して、文章のカテゴライズをしようという目的に使われるみたいです。

```math
P(cat|doc) = \frac{P(cat)P(doc|cat)}{P(doc)}\propto P(cat)P(doc|cat)
```

これが基本形です。

各要素について説明したいと思います。

`P(cat|doc)`は文章(doc)が与えられたときのカテゴリ(cat)である確率です。  
もう少し言うと、文章に「Apple」「iPhone」「MacBookPro」等の単語が含まれていたときに「IT｣などのカテゴリである確率、という意味らしいです。

```math
\frac{P(cat)P(doc|cat)}{P(doc)}
```

`P(doc)` は、どれも共通なので無視して計算することにします。

```math
P(cat)P(doc|cat)
```

`P(cat)` は簡単です。

全文章数が100だとして、ITカテゴリの文章数が50だとすると

```math
P(IT) = \frac{50}{100} = \frac{1}{2}
```

という風に計算できます。

`P(doc|cat)` は少し意味がわからないかもしれません。 カテゴリ(cat)が与えれたときに文章(doc)である確率...? そして、ここがナイーブベイズの肝になる部分です。

ナイーブベイズでは、 `P(doc|cat)` を正確に出さずに、単語の出現の間に独立性を仮定して計算します。

`単語の出現の間に独立性` とは、 例えば `機械`と`学習`は機械学習の分野だとよく出てくるワードかもしれませんが、`機械`と`学習`という単語が独立して出現すると仮定をして単純化することで計算します。

```math
P(doc|cat) = P(word_1 \wedge .... \wedge word_k|cat) = \prod_{i=0}^k P(word_k|cat)
```

と計算します。

```math
\prod
```

は、`Σ`のかける(x)版です。 では次に `P(word|cat)` を計算していきましょう。 これは意味的にはカテゴリ(cat)が与えられた時の単語(word)が出てくる確率なので以下のように計算します。 ( 数式は参考ページにあるので、参考にしてください.. )

```math
P(word_k|cat) = \frac{カテゴリ(cat)内での単語(word)の出現回数}{カテゴリ(cat)に出てきた単語の総数}
```

あとは、これらを使って計算するだけです！！

* 学習データを食わせる
* 目的の文章のスコアリング
* 一番数値の高いカテゴリを返す。

## テクニック

2つキーワードが出てきます。

* ラプラススムージング
* 対数をとる


#### <ラプラススムージング>

`+1`してるだけです。  `ゼロ頻度問題` というのがあるらしいです。 これは何かというと、先ほど P(doc|cat)を単語の出現確率の総乗で表したと思うのですが、積ということは1つ`0` があると、かけて0なので全体で0になってしまいます。

例をあげると、 「IT」というカテゴリで学習していたときに学習データではなかった新規の「Python」という単語がでてきたとしましょう。そうすると..

```math
P(word_k|cat) = \frac{カテゴリ(cat)内での単語(word)の出現回数}{カテゴリ(cat)に出てきた単語の総数}
```

の分子が0になってしまい、

```math
P(Python|IT) = 0 
```

になってしまいます。なので、あらかじめ出現回数に +1しておいて、確率が0になるのを防ごう！！ というのがラプラススムージングというテクニックらしいです。 当然、分母も変わってきます。改めて式を書くと..

```math
P(word_k|cat) = \frac{カテゴリ(cat)内での単語(word)の出現回数 + 1}{カテゴリ(cat)に出てきた単語の総数 + 総単語数}
```

となります。

#### <対数をとる>

サンプルデータでは、大したことないですが実際の計算に当てはめてみると `P(word|cat)`の分母が非常に大きくなってしまうことがあります。

理由は、 単語数が非常に多くなる可能性があるからです。そのようなときにアンダーフローを起こしてしまう可能性があります。

アンダーフローとかオーバーフローの逆で、小数点以下が大きくなりすぎて扱えなくなってしまうことです。

そこで、対数の登場です。 対数をとると同じ底の足し算に置き換えることができるので対数をとって足し算化しても結果は同じになります。

なので、以下を対数をとる形に変えます。

``` math
\prod_{i=0}^k P(word_k|cat)
```

```math
\prod_{i=0}^k \log P(word_k|cat)
```

これらを総合して、最終的な式は以下になります。

```math
P(cat|doc) = \log P(cat) + \sum_{i=0}^k \log P(word_k|cat)
```

参考 : [対数（LOG）の計算と公式！これでもうバッチリ！！](http://kenyu.red/archives/3132.html)

### <次回>

[機械学習初心者がナイーブベイズに手を出してみる (2) - 実装編](http://qiita.com/RINDO/items/8caef9daba5f10caebbe)

で、Pythonを使って実装したいと思います。 (サイト参考にして)

#### 参考

以下のサイトを非常に参考にさせていただきました。ありがとうございました。

* [ナイーブベイズを用いたテキスト分類](http://aidiary.hatenablog.com/entry/20100613/1276389337)
* [[WIP]単純ベイズ分類器がまったく単純じゃないので入門](https://hogehuga.com/post-563/#3)

## 編集履歴

* 2017.11.15 : 最終的な式が誤っていたのでシグマに修正しました
* 2018.10.31 : 条件付き確率の説明が間違っていたので修正しました