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

Posted

技术标签:

【中文标题】在朴素贝叶斯垃圾邮件过滤中结合个体概率【英文标题】:Combining individual probabilities in Naive Bayesian spam filtering 【发布时间】:2011-09-21 18:45:21 【问题描述】:

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

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

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

我的 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;

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

来自维基公式:

我的 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);

在测试字符串“This is not very bad at all.”上,会产生以下输出:

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 cmets 的集合。我实际上是在对这些 cmets 应用我的“垃圾邮件过滤器”。我根据反对票与反对票的数量将个人评论评级为垃圾邮件/火腿:如果反对票少于反对票,则将其视为火腿,否则视为垃圾邮件。

现在,由于语料库类型的原因,实际上很少有单词在垃圾邮件中比在火腿中使用得更多。即,这里是垃圾邮件中出现频率高于 ham 的前十个单词列表。

+-----------+------------+-----------+
| 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 |
+-----------+------------+-----------+

相反,大多数单词在 ham 中的使用比在 ham 中更多。以我的垃圾邮件数量最多的前 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 cmets 语料库中,2100 cmets 被视为垃圾邮件。

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

短语

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)

好的,这很有趣。我在编写此更新时正在做这些示例,因此这是我第一次看到此特定测试用例的结果。我认为我的预测是倒置的。它实际上选择了Ham而不是Spam的概率。这值得验证。

对已知火腿的新测试。

短语

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)

很遗憾,没有。原来这是一个巧合的结果。我开始怀疑 cmets 是否不能这么容易量化。也许一个坏评论的性质与垃圾邮件的性质有很大的不同。

也许只有当您拥有特定词类的垃圾邮件时,垃圾邮件过滤才有效?


最终更新

正如回复中所指出的,奇怪的结果是由于语料库的性质造成的。使用没有明确定义垃圾邮件贝叶斯分类的评论语料库不会执行。由于任何一条评论都可能(并且很可能)收到不同用户的垃圾邮件和非垃圾邮件评级,因此不可能为垃圾邮件 cmets 生成硬分类。

最终,我想生成一个评论分类器,该分类器可以根据针对评论内容调整的贝叶斯分类来确定评论帖子是否会装饰业力。我可能仍然会研究调整分类器以发送垃圾邮件,看看这样的分类器是否可以猜测评论系统的业力响应。但现在,这个问题得到了回答。谢谢大家的意见。

【问题讨论】:

+1 用于使用数学表达式!和代码!和一个完整的,写得很好的解释。我希望我可以投票 +10。 嗨杰里米。您最终是否使用此算法进行垃圾邮件过滤。我想做一些类似的事情,但也得到了不一致的结果。 嘿,保罗。我这样做是为了练习,它从未被用于任何事情。值得一提的是,如下所述,我发现当我提供相同的火腿/垃圾邮件示例的语料库时,结果更符合我的预期。 【参考方案1】:

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

尝试从您的垃圾邮件文件夹中运行一些真正的垃圾邮件,在那里您会遇到像 0.8 这样的概率。猜猜为什么垃圾邮件发送者有时会尝试在隐藏的框架中发送一张报纸和消息:)

【讨论】:

不幸的是,正如上面附加信息中所讨论的那样,即使评估垃圾邮件也会导致不受欢迎的小概率。 嗯,你的问题是(假设有 40000 个帖子,其中大约 2000 个是垃圾邮件)你有......没有足够的垃圾邮件。通常在电子邮件通信中会有 95-98% 的垃圾邮件,而您的情况正好相反。这就是为什么贝叶斯过滤器看起来像是检测火腿消息的原因。我看到的另一个问题是,最垃圾的词有 0.625 的概率成为垃圾邮件——这还不够。我对您的建议是获取真正的垃圾邮件数据库并用它来教您的过滤器 - 垃圾邮件毕竟没有什么不同,无论它是电子邮件还是论坛帖子。【参考方案2】:

如果您的过滤器没有偏差 (Pr(S)=Pr(H) = 0.5),则:“学习的消息集还应符合关于垃圾邮件和正常邮件之间重新分配的 50% 假设,即spam 和 ham 的数据集大小相同。"

这意味着您应该教您的贝叶斯过滤器处理类似数量的垃圾邮件和非正常邮件。说 1000 条垃圾邮件和 1000 条垃圾邮件。

我假设(未检查)如果您的过滤器是有偏见的,那么学习集应该符合关于任何消息都是垃圾邮件的假设。

【讨论】:

【参考方案3】:

关于补偿消息长度的想法,您可以为每个集合估计消息单词成为特定单词的概率,然后使用泊松分布来估计包含该特定单词的 N 个单词的消息的概率。

【讨论】:

以上是关于在朴素贝叶斯垃圾邮件过滤中结合个体概率的主要内容,如果未能解决你的问题,请参考以下文章

朴素贝叶斯垃圾邮件过滤问题

如何在垃圾邮件过滤中嵌入带有朴素贝叶斯分类器的关联规则?

使用朴素贝叶斯分类器过滤垃圾邮件

机器学习贝叶斯算法详解 + 公式推导 + 垃圾邮件过滤实战 + Python代码实现

在贝叶斯垃圾邮件过滤器中计算令牌成为垃圾邮件的概率

使用朴素贝叶斯算法简单实现垃圾邮件过滤之算法介绍实现过程