2011-06-24 16 views
17

私は現在蓄積しているコーパスを分析してスパムフィルタを生成しようとしています。Naive Bayesianスパムフィルタリングで個々の確率を組み合わせる

私は分類コードを開発するためにウィキペディアのエントリhttp://en.wikipedia.org/wiki/Bayesian_spam_filteringを使用しています。

pr(S|W) = (pr(W|S)*pr(S))/(pr(W|S)*pr(S) + pr(W|H)*pr(H))

私のPHPコード:

public function pSpaminess($word) 
{ 
    $ps = $this->pContentIsSpam(); 
    $ph = $this->pContentIsHam(); 
    $pws = $this->pWordInSpam($word); 
    $pwh = $this->pWordInHam($word); 
    $psw = ($pws * $ps)/($pws * $ps + $pwh * $ph); 
    return $psw; 
} 
メッセージがスパムはそれがウィキから次の式を実装することにより、特定の単語が含まれていることを与えていることを

は、私は確率を計算するコードを実装しました

「個々の確率を組み合わせる」セクションに従って、テストメッセージ内のすべてのユニークワードの確率を組み合わせてスパム性を判断するコードを実装しました。ウィキ式から

p=(p1*pn)/((p1*pn)+(1-p)(1-pn))

私のPHPコード: "これがすべてで非常に悪いわけではない" テスト文字列で

public function predict($content) 
{ 
    $words = $this->tokenize($content); 
    $pProducts = 1; 
    $pSums = 1; 
    foreach($words as $word) 
    { 
     $p = $this->pSpaminess($word); 
     echo "$word: $p\n"; 
     $pProducts *= $p; 
     $pSums *= (1 - $p); 
    } 
    return $pProducts/($pProducts + $pSums); 
} 

は、次の出力が生成され:

C:\projects\bayes>php test.php 
this: 0.19907407407407 
isn't: 0.23 
very: 0.2 
bad: 0.2906976744186 
at: 0.17427385892116 
all: 0.16098484848485 
probability message is spam: float(0.00030795502523944) 

ここに私の質問があります。事実上の確率は正しくありますか?私は有効な個々の単語の確率を生成していると仮定し、組み合わせ方法は正しいですか?

私の懸念は、実際には計算の確率が非常に低いことです。私はより大きなテストメッセージでそれをテストし、結果として10個以上のゼロがある科学記法で確率を上げました。私は10番か100番の場所で値を期待していました。

問題は私のPHP実装にあると思っていますが、私がwikipediaの組み合わせ関数を調べると、数式の配当は分数の積になります。私は、複数の確率の組み合わせがどのように0.1%以上の確率で終わるのか見ていない。

メッセージが長くなるほど確率スコアは低くなりますが、小規模および大規模のテストケースでスパム/ハムを正しく予測するにはどのようにしてスパムの割り当てを補うことができますか?


追加情報

私のコーパスは、実際にはおよそ40Kのredditコメントのコレクションです。私は実際にこれらのコメントに対して私の "迷惑メールフィルタ"を適用しています。私は個々のコメントを下位票への票数に基づいてスパム/ハムとして評価しています。票数が票数を下回っている場合、票はハム、そうでなければ迷惑メールとみなされます。

コーパスタイプのため、実際にはハムよりもスパムで使用される単語はほとんどありません。つまり、ハムよりも頻繁にスパムに表示される単語の上位10個のリストです。

逆に、ほとんどの単語は、ハムよりもハムで非常に豊富に使用されています。たとえば、スパム件数が最も多い言葉の上位10リストを考えてみましょう。

+------+------------+-----------+ 
| word | spam_count | ham_count | 
+------+------------+-----------+ 
| the |  4884 |  17982 | 
| to |  4006.5 | 14658.5 | 
| a |  3770.5 | 14057.5 | 
| of |  3250.5 | 12102.5 | 
| and |  3130 |  11709 | 
| is |  3102.5 | 11032.5 | 
| i |  2987.5 | 10565.5 | 
| that |  2953.5 | 10725.5 | 
| it |  2633 |  9639 | 
| in |  2593.5 | 9780.5 | 
+------+------------+-----------+ 

ご覧のとおり、スパムの使用頻度は、ハムの使用頻度よりも大幅に低くなっています。 40kコメントの私のコーパスでは、2100件のコメントはスパムとみなされます。

以下示唆したように、次のようにスパム率と考えるポストにテストフレーズ:

フレーズ

Cops are losers in general. That's why they're cops. 

分析:

C:\projects\bayes>php test.php 
cops: 0.15833333333333 
are: 0.2218958611482 
losers: 0.44444444444444 
in: 0.20959269435914 
general: 0.19565217391304 
that's: 0.22080730418068 
why: 0.24539170506912 
they're: 0.19264544456641 
float(6.0865969793861E-5) 

これによると、非常に低いがありますこれがスパムである可能性があります。

フレーズ

Bill and TED's excellent venture? 

分析

C:\projects\bayes>php test.php 
bill: 0.19534050179211 
and: 0.21093065570456 
ted's: 1 
excellent: 0.16091954022989 
venture: 0.30434782608696 
float(1) 

さて、これは興味深いです:しかし、場合、私は今、ハムのコメントを分析することでした。私はこのアップデートを構成しているので、これらのサンプルを実行していますので、この特定のテストケースの結果を見たのは初めてです。私の予測は逆転していると思う。実際にはスパムの代わりにハムの確率を選んでいます。これは検証に値する。

既知のハムについての新しい試験。

フレーズ

Complain about $174,000 salary being too little for self. Complain about $50,000 a year too much for teachers. 
Scumbag congressman. 

分析

C:\projects\bayes>php test.php 
complain: 0.19736842105263 
about: 0.21896031561847 
174: 0.044117647058824 
000: 0.19665809768638 
salary: 0.20786516853933 
being: 0.22011494252874 
too: 0.21003236245955 
little: 0.21134020618557 
for: 0.20980452359022 
self: 0.21052631578947 
50: 0.19245283018868 
a: 0.21149315683195 
year: 0.21035386631717 
much: 0.20139771283355 
teachers: 0.21969696969697 
scumbag: 0.22727272727273 
congressman: 0.27678571428571 
float(3.9604152477223E-11) 

残念ながらありません。それは偶然の結果であったことが分かります。おそらくコメントを簡単に数量化できないのだろうかと思い始めています。おそらく、悪いコメントの性質は、スパムメッセージの性質とあまりにも大きく異なります。

スパムフィルタリングは、特定の単語クラスのスパムメッセージがある場合にのみ機能する場合がありますか?


最終更新

回答で指摘したように、奇妙な結果は、コーパスの性質のためにしました。スパムの明示的な定義がない場合のコメントコーパスの使用ベイジアン分類は実行されません。いずれかのコメントが様々なユーザによってスパムとハムの両方の評価を受け取る可能性がある(そして可能性が高い)ので、スパムコメントのために厳密な分類を生成することはできない。

究極的には、コメント投稿が、コメントコンテンツに調整されたベイジアン分類に基づいてカルマを飾るかどうかを判断できるコメント分類子を生成したかったのです。私は依然として分類器のチューニングを調査してスパムメッセージを電子メールで送信し、そのような分類器がコメントシステムのカルマ応答で推測できるかどうかを調べることがあります。しかし、今のところ、質問に答えています。入力いただきありがとうございます。

+2

数式を使用すると+1!そしてコード!そして完全な、よく書かれた説明。私は+10アップアップすることができたらいいと思う。 – wallyk

+0

こんにちはジェレミー。スパムフィルタリングにこのアルゴリズムを使用することになりましたか?私は似たようなことをやろうとしていますが、矛盾した結果が出ます。 –

+0

ヘイ・ポール。私はこれを運動として行いました。それは何にも使われていませんでした。それが価値があることについては、以下に述べるように、同じハム/スパムの例のコーパスを提供したときの結果が私の期待とより一致していることがわかりました。 –

答えて

2

電卓だけで、あなたが掲示した非スパムのフレーズは大丈夫です。その場合、$ pProductsには$ pSumsより小さい2桁の大きさがあります。

あなたの迷惑メールフォルダから実際のスパムを実行してみましょう。ここでは、0.8のような確率を満たしています。そして、なぜスパマーがメッセージと共に隠れたフレームに新聞紙を送るのか推測してください:)

+0

残念なことに、上記の追加情報で説明したように、スパムメッセージを評価しても、望ましくない小さな確率が生じます。 –

+2

あなたの問題は、あなたが持っているスパムが十分ではないことです(2000年頃に投稿された投稿が40000件あります)。通常、電子メール通信には、スパムの95〜98%のようなものがあります。そのため、ベイジアンフィルタはハムメッセージを検出するように見えます。私が見る他の問題は、最もスパムのある単語が0.625のようなスパムである可能性があるということです。それだけでは不十分です。 私のアドバイスは、実際のスパムデータベースをどこかに取得してフィルタを教えることです。電子メールやフォーラムの投稿であっても、迷惑メールメッセージはそれほど変わっていません。 – meteor

2

フィルタがバイアスされていない場合(Pr(S)= Pr(H)= 0.5)学習したメッセージのセットがスパムとハム間の再分割に関する50%の仮説、すなわちスパムとハムのデータセットが同じサイズであるという仮説に従うこともお勧めします。

これは、似たような量のスパムとハムメッセージに対してベイジアンフィルタを教えなければならないことを意味します。 1000のスパムメッセージと1000のハムメッセージを表示します。

あなたのフィルタがバイアスをかけられている場合、学習セットはスパムであるメッセージに関する仮説に従うべきであると私は仮定します。

0

メッセージの長さを補正するという考えでは、特定の単語であるメッセージワードの確率を各セットごとに推定し、ポアソン分布を使用して、その特定の単語を含むNワードのメッセージの確率を推定できます。

関連する問題