■
PHPでベイジアンフィルタ (実践編)
実践編です。
ベイジアンフィルタを使ったアプリケ-ションの流れは、大きく分けて以下の3段階になります。
パターン学習は、特定の文書(単語のセット)がどのクラスに所属するかを指定します。 これにより出現頻度のデータベース(コーパス)が更新されて、次回以降の分類精度を向上させることができます。 通常は、クラスを最初に設定して、以降は学習と分類を繰り返すような感じになると思います。
…ということで、クラスの定義から。
何故かNaiveBayesianStorageには、カテゴリ操作のインターフェースが提供されていないので、手作業で行います。 addCategory()とかdeleteCategory()とか追加してあげると便利なんですが。
とりあえず一般的な例で、メールの文章を適当に登録してSPAM判定が行えるかどうか試してみます。 クラス毎にパターンを覚えさせる必要があるので、ここではSPAMメールの文章と、普通のメールの文章を各10件ずつ用意して登録します。 NaiveBayesian::train()で登録させるので、登録用のPHPスクリプトなんかを適当に。
NaiveBayesian::train() の $docid には文書に付ける一意のID(登録済みのIDと重複しなければなんでもいいです)を指定します。
$cat にはカテゴリ名、$docには文書を渡します。単語の抽出は自動的に行われます。
で、メインであるところの文書分類。
判定したい文章を渡して NaiveBayesian::categorize() すると各クラスに所属する確率が返る…はず。
出力結果。ちゃんとSPAM判定してくれている模様。
ここで結果が間違っている場合は、上と同じやり方で NaiveBayesian::train() を使って学習させます。
SPAMフィルタの場合は分類失敗よりも誤検出のほうが被害が大きいので、このときの確率が0.90以上の場合のみSPAM判定するみたいな分類をしたほうがいいかもしれません。 カテゴリが複数存在する場合は、一番確率が高いものを選択すれば良いと思います。
といった感じで、比較的簡単にベイジアンフィルタが使えそうな感じではあるんですが、たまに確率が1.0を超えたりする場合があって微妙に謎です。 どこかでやり方間違えてるのかなー。
こんなのとか、こんなのとか。
学習パターン数が少ないと発生しやすいみたいなので、それなりのパターンを登録してあげる必要があるかもしれないですね。 とりあえず10件や20件では全然少ないので、1000件くらいのパターンは欲しいかも。
ベイジアンフィルタを使ったアプリケ-ションの流れは、大きく分けて以下の3段階になります。
- カテゴリ(クラス)定義
- パターン学習
- 文書分類
パターン学習は、特定の文書(単語のセット)がどのクラスに所属するかを指定します。 これにより出現頻度のデータベース(コーパス)が更新されて、次回以降の分類精度を向上させることができます。 通常は、クラスを最初に設定して、以降は学習と分類を繰り返すような感じになると思います。
…ということで、クラスの定義から。
何故かNaiveBayesianStorageには、カテゴリ操作のインターフェースが提供されていないので、手作業で行います。 addCategory()とかdeleteCategory()とか追加してあげると便利なんですが。
mysql> insert into nb_categories (category_id) VALUES ('spam');
mysql> insert into nb_categories (category_id) VALUES ('nospam');
とりあえず一般的な例で、メールの文章を適当に登録してSPAM判定が行えるかどうか試してみます。 クラス毎にパターンを覚えさせる必要があるので、ここではSPAMメールの文章と、普通のメールの文章を各10件ずつ用意して登録します。 NaiveBayesian::train()で登録させるので、登録用のPHPスクリプトなんかを適当に。
$login = 'username'; // MySQL user
$pass = 'password'; // MySQL password
$db = 'nb';
$server = 'localhost';
include_once 'class.naivebayesian.php';
include_once 'class.naivebayesianstorage.php';
include_once 'class.mysql.php';
include_once 'class.naivebayesian_jp.php'; // NaiveBayesianJP
$nbs = new NaiveBayesianStorage($login, $pass, $server, $db);
$nb = new NaiveBayesianJP($nbs);
$pattern_spam = array(
'25歳人妻です旦那との夜の生活が3ヶ月に一度です。新婚の頃は…',
'現在、当サイトにご登録されている女性会員様(約48万人)の…',
'業界各方面から多大なる絶賛を得ています。過去には無かった体験が…',
'人妻が大好き!または人妻に興味がある!という方だけ…',
'私は市内の某私立高校に通う女子高生です。実は先日39歳になる母が…',
...
);
foreach ($spams as $idx => $doc) {
$cat = 'spam';
$docid = $cat .'_'. $idx;
if ($nb->train($docid, $cat, $doc)) {
$nb->updateProbabilities();
}
}
// 普通のメールの登録も同様に
で、メインであるところの文書分類。
判定したい文章を渡して NaiveBayesian::categorize() すると各クラスに所属する確率が返る…はず。
$nbs = new NaiveBayesianStorage($login, $pass, $server, $db);
$nb = new NaiveBayesianJP($nbs);
$text = 'ドスケベな男女に朗報です△今すぐにエッチがしたい!近所で…';
$scores = $nb->categorize($text);
while(list($cat,$score) = each($scores)) {
echo "$cat : $score\n";
}
ここで結果が間違っている場合は、上と同じやり方で NaiveBayesian::train() を使って学習させます。
spam : 0.99946305424632
nospam : 0.032765884645883
SPAMフィルタの場合は分類失敗よりも誤検出のほうが被害が大きいので、このときの確率が0.90以上の場合のみSPAM判定するみたいな分類をしたほうがいいかもしれません。 カテゴリが複数存在する場合は、一番確率が高いものを選択すれば良いと思います。
といった感じで、比較的簡単にベイジアンフィルタが使えそうな感じではあるんですが、たまに確率が1.0を超えたりする場合があって微妙に謎です。 どこかでやり方間違えてるのかなー。
spam : 6.1633758754325E-10
nospam : 1
spam : 1
nospam : 9.547379900121E-13
学習パターン数が少ないと発生しやすいみたいなので、それなりのパターンを登録してあげる必要があるかもしれないですね。 とりあえず10件や20件では全然少ないので、1000件くらいのパターンは欲しいかも。
posted at 04:06 [ /tech ]
「
「
「






