$yuzu->log();

技術ネタなど。

【機械学習】ベイジアンフィルタ

ベイジアンフィルタとは

ベイジアンフィルタ (Bayesian Filter)とはナイーブベイズ分類を応用したもので、対象となるデータを解析・学習し分類する為のフィルタです。 現状では迷惑メールフィルタやスパム投稿などの判定で利用されています。

ベイズの定理

ベイズの定理(Bayes' theorem)とは条件付き確率に関して成り立つ定理で、トーマス・ベイズによって示されたものです。

 \displaystyle
  P(B|A) = \frac{P(A|B)P(B)}{P(A)}
  • \( (A) \)とは\( A \)が起きる確率
  • \( P(B) \)とは、\( B \)が起きる確率(事前確率)
  • \( P(A|B) \)とは、\( B \)のあとで\( A \)が起きる確率(条件付き確率、尤度)
  • \( P(B|A) \)とは、\( A \)のあとで\( B \)が起きる確率(条件付き確率、事後確率)

条件付き確率とは

条件付き確率とは、ある事象Aが起こる条件下で、別の事象Bが起こる確率のことです。これを

\( P(B|A) \)

と表します。 たとえば

  • \( P(雨) \) = 雨の降る確率
  • \( P(事故) \) = 交通事故の発生確率

とすると雨が降っていて、交通事故が発生する確率は

\( P(事故|雨) \)

と表せます。

次はベイズの定理を使って実践的な問題を解いてみましょう。

ベイズの定理から見る膵臓ガン発見の検査方法

www.huffingtonpost.jp

15歳の少年が膵臓がん発見の画期的な方法を開発したことがについて、この検査方法が統計的にどのような意味をもつのかをベイズの定理を使って計算してみます。

  • \( p1 \) = 被験者が陽性になる確率
  • \( p2 \) = 被験者が陰性になる確率
  • \( p3 \) = 被験者ががん患者である確率
  • \( X \) = 被検査者はガンであるという事象
  • \( Y\) = 検査の結果、被検査者はガンであると示す事象

とすると

  • \( p1 = P(X|Y) \)
  • \( p2 = P(X^{c}|Y^{c}) \)
  • \( p3 = P(Y) \)

と表せる。 \( X^{c} \) や \( Y^{c} \) はそれぞれの補事象。

ここで \( P(X) \) は検査結果が真陽性となる確率と偽の陰性となる確率を足したものなので、

\( P(X) = P(Y)P(X|Y) + P(Y^{c})P(X|Y^{c}) \)

さらに、

\( P(X|Y^{c}) = 1-P(X^{c}|Y^{c}) \)

のため、

ベイズの定理より

 {
\begin{align} 
  P(Y|X) &= \frac{P(X|Y)P(Y)}{P(X)} \\
&=  \frac{P(X|Y)P(Y)}{P(Y)P(X|Y) + P(Y^{c})P(X|Y^{c})} \\
&=  \frac{P(X|Y)P(Y)}{P(Y)P(X|Y) + P(Y^{c})(1-P(X^{c}|Y^{c}))} \\
&= \frac{p1p3}{p1p3+(1-p3)(1-p2)} 
      \end{align}
}

となります。

実際の数値を当てはめてみましょう。 2008年の膵臓がんの患者数は29,584人、総人口は1億2769万2000人なので

\( p3 = 0.23168 * 10^{-3} \)

また簡単のために p1, p2をひとまとめに誤検出の確率と仮定してp1=p2=qおくと、\( P(Y|X) \) が70%となるようなqは

\( q=0.99990 \)

となります。 このことから、99.99%の精度をもつ検出方法でも実際には30%も見逃してしまうということがわかります。

さらに、「400倍の精度で検査できる」という部分を誤検出の確率が400分の1になったという意味だと解釈して、

\( q' = 1- \frac{(1-q)}{400} \)

とおいてがん患者が検査の結果実際に陽性だと判定される確率を再度計算すると

\( P(Y|X) = 0.99892 \)

となります。これは30%見逃していたのが1%まで減ったということです。 実に素晴らしい結果ですね。

次回はベイズの定理を使ったナイーブベイズ分類器のお話です。

yuzurus.hatenablog.jp

ベイズ統計学入門

ベイズ統計学入門

【機械学習】ナイーブベイズ分類アルゴリズムを利用した迷惑メールフィルタ実装例

ナイーブベイズ分類器とは?

ベイズの定理を利用した分類手法です。 ベイズの定理について知りたい方は下記の参照下さい。

yuzurus.hatenablog.jp

 \displaystyle

ナイーブベイズ分類は文章をカテゴリ分けする際に、テキスト中の単語の出現率を調べます。 その際、その文章をどのカテゴリに分類するのが相応しいか調べるのです。

判定の際に \( P(B|A) \) は1つの確率ではなく、複数のカテゴリ中で、どのカテゴリになる確率が一番高いかを表す情報になります。 この時 \( P(A) \) は入力テキストが与えられる確率となります。

しかし、どのカテゴリを判定するにしても同じ入力になるため、同じ値と考えて良いこととします。するとナイーブベイズ分類は次のように表せます。

\( P(B|A) = P(B)P(A|B) \)

この時の \( P(B) \) は事前確率で、各カテゴリに分類される確率を表しています。

これは単なるベイズ分類器です。ナイーブベイズ分類器は確率分布 \(P(A|B) \) をシンプルな分布に限定します。

入力テキストAに関して、単語の集合と考えて、多次元変数と考えると

\( A={a1,a2,a3,…,aN} \)

と表せます。すると \(P(A|B) \) は

{ \displaystyle
P(A|B) = \prod_{i=1}^{N} P(a_i|B)
}

となります。

ナイーブベイズ分類を利用して迷惑メールフィルタを作ってみる

ナイーブベイズ分類アルゴリズムを内包したライブラリ「fieg/bayes」を利用して迷惑メールフィルタを作ってみましょう!
単語分類のためにMecabのインストールとphp-mecabのインストールが必要になります。

composerを利用してfieg/bayesというライブラリをインストールします

composer require fieg/bayes

単語分類器 MecabTokenizer.php

<?php
require_once 'vendor/autoload.php';
require_once 'mecab.inc.php';

use Fieg\Bayes\TokenizerInterface;

class MecabTokenizer implements TokenizerInterface {
  public function tokenize($str) {
    return mecab_parse_simple($str);
  }
}

単語分類器を利用したプログラムbayes-filter.php

<?php
require_once 'vendor/autoload.php';
require_once 'MecabTokenizer.php';

use Fieg\Bayes\Classifier;

// 単語分類器と分類器の生成
$tokenizer = new MecabTokenizer();
$classifier = new Classifier($tokenizer);

// 学習
$classifier->train('迷惑メール', '年収1000万を確実に稼ぐ方法');
$classifier->train('迷惑メール', '【FX】1年で資産120倍!このスゴイ講義が無料。ちょっと信じられません・・・');
$classifier->train('迷惑メール', '月利40%のモニター募集');
$classifier->train('迷惑メール', '【年利174%】99.9%の確率で含み損が利益になるプロ技');
$classifier->train('迷惑メール', '【2日で1億1800万円】英国EU離脱騒動で稼いだオトコの正体');
$classifier->train('迷惑メールでない', '暮らしを便利にするマストアイテムを65%OFF');
$classifier->train('迷惑メールでない', 'アンケートにご回答いただくと30ポイントプレゼント【楽天】(2016/09/17)');
$classifier->train('迷惑メールでない', '【お急ぎください!】9月連休出発高速バス予約ラストチャンス!');
$classifier->train('迷惑メールでない', 'Amazon.co.jpからポイント付与についてお知らせ');
$classifier->train('迷惑メールでない', '【住信SBIネット銀行】定額自動振込サービス振込受付のお知らせ  ');

$s = '【衝撃映像】『日給1100万円確定』の瞬間を捉えた!';
$r1 = $classifier->classify($s);
echo "--- $s\n";
print_r($r1);

$s = '【早割】特大和洋中おせち♪国産南高梅の木箱ギフトなど【楽天】(2016/09/18)';
$r2 = $classifier->classify($s);
echo "--- $s\n";
print_r($r2);

これを実行してみると

php bayes-filter.php
--- 【衝撃映像】『日給1100万円確定』の瞬間を捉えた!
Array
(
    [迷惑メール] => 0.9
    [迷惑メールでない] => 0.1
)
--- 【早割】特大和洋中おせち♪国産南高梅の木箱ギフトなど【楽天】(2016/09/18)
Array
(
    [迷惑メールでない] => 0.99980407523511
    [迷惑メール] => 0.00019592476489028
)

簡単なテストですが、ちゃんと分類されてますね!

ソースはここにおいておきます。

github.com