结合朴素贝叶斯垃圾邮件过滤中的个体概率

Jer*_*son 19 php probability spam-prevention

我目前正试图通过分析我积累的语料库来生成垃圾邮件过滤器.

我正在使用维基百科条目http://en.wikipedia.org/wiki/Bayesian_spam_filtering来开发我的分类代码.

我已经实现了代码来计算消息是垃圾邮件的概率,因为它包含一个特定的单词,通过从wiki实现以下公式:

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;
}
Run Code Online (Sandbox Code Playgroud)

根据组合个体概率部分,我实现了代码,以组合测试消息中所有唯一单词的概率来确定垃圾邮件.

从维基公式:

P =(P1*PN)/((P 1*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);
}
Run Code Online (Sandbox Code Playgroud)

在测试字符串"这不是很糟糕.",产生以下输出:

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)
Run Code Online (Sandbox Code Playgroud)

这是我的问题:我是否正确实施了合并个体概率?假设我正在生成有效的单个单词概率,那么组合方法是否正确?

我担心的是计算的结果概率非常小.我已经在一个更大的测试消息上进行了测试,最终得出了超过10个零位的科学记数法.我期待在10或100位的价值.

我希望问题出在我的PHP实现中 - 但是当我从维基百科检查组合函数时,公式的被除数是分数的乘积.我不知道多个概率的组合最终会如何超过0.1%的概率.

如果是这种情况,消息越长,概率分数越低,如何补偿垃圾邮件配额以正确预测小型和大型测试案例的垃圾邮件/火腿?


附加信息

我的语料库实际上是大约40k reddit评论的集合.我实际上是在对这些评论应用我的"垃圾邮件过滤器".我根据向上投票的票数来评判个人评论为垃圾邮件/火腿:如果投票少于投票,则认为是火腿,否则是垃圾邮件.

现在,由于语料库类型,实际上垃圾邮件中使用的单词实际上比火腿更少.也就是说,这是垃圾邮件中出现的十大字词列表.

+-----------+------------+-----------+
| word      | spam_count | ham_count |
+-----------+------------+-----------+
| krugman   |         30 |        27 |
| fetus     |       12.5 |       7.5 |
| boehner   |         12 |        10 |
| hatred    |       11.5 |       5.5 |
| scum      |         11 |        10 |
| reserve   |         11 |        10 |
| incapable |        8.5 |       6.5 |
| socalled  |        8.5 |       5.5 |
| jones     |        8.5 |       7.5 |
| orgasms   |        8.5 |       7.5 |
+-----------+------------+-----------+
Run Code Online (Sandbox Code Playgroud)

相反,大多数单词在火腿中的使用量比火腿大得多.例如,我的垃圾邮件数量最多的前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 |
+------+------------+-----------+
Run Code Online (Sandbox Code Playgroud)

如您所见,垃圾邮件使用频率远低于火腿使用频率.在我的40k评论的语料库中,2100评论被认为是垃圾邮件.

如下所示,帖子上的测试短语被视为垃圾邮件率如下:

短语

Cops are losers in general. That's why they're cops.
Run Code Online (Sandbox Code Playgroud)

分析:

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)
Run Code Online (Sandbox Code Playgroud)

据此,这是垃圾邮件的概率极低.但是,如果我现在要分析火腿评论:

短语

Bill and TED's excellent venture?
Run Code Online (Sandbox Code Playgroud)

分析

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

好的,这很有趣.我正在做这些例子,因为我正在撰写此更新,所以这是我第一次看到这个特定测试用例的结果.我认为我的预测是倒置的.它实际上挑出了汉姆而不是垃圾邮件的概率.这值得验证.

对已知火腿的新测试.

短语

Complain about $174,000 salary being too little for self.  Complain about $50,000 a year too much for teachers.
Scumbag congressman.
Run Code Online (Sandbox Code Playgroud)

分析

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)
Run Code Online (Sandbox Code Playgroud)

很不幸的是,不行.事实证明这是一个巧合的结果.我开始怀疑是否可能无法轻易量化评论.也许坏评论的性质与垃圾邮件的性质差别太大.

也许情况可能是垃圾邮件过滤仅在您拥有特定的垃圾邮件单词类时才有效?


最后更新

正如回复中所指出的,奇怪的结果是由于语料库的性质.使用评论语料库,其中没有明确定义的垃圾邮件贝叶斯分类不执行.由于可能(并且可能)任何一个评论可能会被各种用户同时接收垃圾邮件和火腿评级,因此无法为垃圾评论生成硬分类.

最终,我想生成一个评论分类器,可以确定评论帖是否会根据调整评论内容的贝叶斯分类来提供业力.我仍然可以调查分类器调整垃圾邮件的电子邮件,看看这样的分类器是否可以猜测评论系统的业力响应.但就目前而言,问题已得到解答.谢谢大家的意见.

met*_*eor 1

仅使用计算器进行变化,您发布的非垃圾邮件短语似乎没问题。在这种情况下,$pProducts 比 $pSums 小几个数量级。

尝试从垃圾邮件文件夹中运行一些真正的垃圾邮件,您会遇到类似 0.8 的概率。猜猜为什么垃圾邮件发送者有时会尝试将一张报纸放在隐藏的框架中与消息一起发送:)

  • 好吧,你的问题是(假设有 40000 个帖子,其中大约 2000 个是垃圾邮件)你...没有足够的垃圾邮件。通常在电子邮件通信中,95-98% 都是垃圾邮件,但反之亦然。这就是为什么贝叶斯过滤器看起来像是检测火腿消息。我看到的另一个问题是,垃圾邮件最多的单词成为垃圾邮件的概率约为 0.625 - 这还不够。我对您的建议是找到真正的垃圾邮件数据库并用它来教您的过滤器 - 垃圾邮件毕竟没有那么不同,无论它是电子邮件还是论坛帖子。 (2认同)