naive贝叶斯
前提假设:邮件中出现的各个词之间完全独立、不相关。
【前提假设未必正确但此模型效果很好】
(贝叶斯公式)
上式左端理解为F1, F2,,,,Fn同时出现时, 属于类别C的概率。
式中分子就是
根据前提假设F之间独立,因此
p(Fi|C, Fj)理解为当Fj出现在类别C中时,Fi的条件概率
因此判别由单词F1,,,Fn构成的待识别邮件属于哪个类, 可以求使得上式最大的C即可
当只有两类:垃圾邮件C1、正常邮件C2时,可以直接计算p(C1|F1,F2,,,Fn)与p(C2|F1,F2,,,Fn)
http://en.wikipedia.org/wiki/Naive_Bayes_classifier
在使用贝叶斯实现bogofilter中, 只需要求p(垃圾类|待识别邮件),
对应的,C就表示垃圾类别; p(C)就表示垃圾样本数/总样本数, p(Fi|C)表示第i个词出现在垃圾邮件样本中的概率。
如果计算得到的p很大,超过spam_cutoff就认为是垃圾邮件.
robinson-fisher算法改进
robinson-fisher算在在传统naïve bayes的基础之上逐步做了如下几点改进:
1 使用f(w)代替p(w):
p(w)表示w在垃圾邮件中出现的概率(就是p(Fi|C));使用fw代替pw。
pw = ((bad / badmsgs) / (bad / badmsgs + good / goodmsgs));
【
假设ham为10, spam为20;
w在ham中出现4, good;
w在spam中出现2,bad。
那么pw就是0.2
】
fw计算公式:
(s * x) + (n * p(w))
f(w) = --------------------
s + n
s,x都是robinson系数robs,robx; n是w出现的总次数
#define ROBS 0.0178 /* Robinson's s */
#define ROBX 0.52 /* Robinson's x */
这两个值可以使用bogofilter根据我们的样本库来得到推荐值。
对应bogofilter的代码如下:
//good表示w出现在ham中的次数,bad则为在spam中的次数
uint n = good + bad;
fw = (robs * robx + n * pw) / (robs + n);
//src/score.c
2 robinson改进贝叶斯链的计算公式
贝叶斯链就是计算
C表示垃圾邮件类别; 当该值大于spam_cutoff时就认为是垃圾邮件
robinson改进
P = 1 - ((1-p1)*(1-p2)*...*(1-pn))^(1/n) [spamminess]
Q = 1 - (p1*p2*...*pn)^(1/n) [non-spamminess]
S = (P - Q) / (P + Q) [combined indicator]
用S代表待识别邮件属于垃圾邮件的概率。(p1, p2, p3表示邮件中出现的单词在垃圾邮件中的概率;实际bogofilter使用了第一个改进得到的fw代替pi)
((1-p1)*(1-p2)*...*(1-pn))^(1/n), (p1*p2*...*pn)^(1/n) 表示开n次方,称作robinson geometric mean, robinson几何均值
S介于[-1,1]之间,可做线性处理成S = (1 + (P - Q) / (P + Q))/2
3 fisher对P, Q,S的求法做了改进
如上P, Q, S的计算公式
改进之后的计算公式://src/score.c : get_spamicity
Fisher's method uses an inverse chi-squared function, prbx, to get the probability associated with -2 times the sum of the logs of f(w) with 2n degrees of freedom:
P = prbx(-2 * sum(ln(1-f(w))), 2*n)
Q = prbx(-2 * sum(ln(f(w))), 2*n)
S = (1 + Q - P) / 2
Prbx, 就是函数gsl_cdf_chisq_Q(double x, double k), 计算k个符合标准正态分布的随机变量之和x 的cummulative distribution(累积分布函数):
因此,prbx的作用就是下图式中以第1个参数为横坐标x, 第2个参数为k,得到其纵坐标
http://en.wikipedia.org/wiki/Chi-square_distribution
http://linux.math.tifr.res.in/manuals/html/gsl-ref-html/gsl-ref_16.html
code:(代码中的prbf就是上文中的prbx)
score.p_pr = prbf(-2.0 * score.p_ln, sp_df); /* compute P */
score.q_pr = prbf(-2.0 * score.q_ln, ns_df); /* compute Q */
score.spamicity = (1.0 + score.q_pr - score.p_pr) / 2.0;
【prbx作用同算术均值,几何均值类似, 是一种更复杂的统计推断方式:假设已有k个独立、符合标准正态分布的随机变量之和为x,推断这k个随机变量同时出现时这个标准正态分布函数的累积分布值,也就是属于垃圾邮件的概率】
4 优点/比较
http://www.bgl.nu/bogofilter/BcrFisher.html
改进1,2 改进1,2,3 Naïve bayes
Robinson-geometric-mean Robinson-Fisher Bayes Chain Rule
--- ---- --------
/ / |
/ | |
/ | |
/ | |
/ | |
/ / |
--- ---- --------
图中值均介于[0,1]之间, 为1表示肯定是垃圾邮件,为0表示是正常邮件。
使用样本对检验上述三个算法效果图如上。
第一个图中[0, 0.55]被识别为正常邮件, [0.45, 1]被识别为垃圾邮件, 存在交集, 甚至无法选择合适的spam_cutoff
第三个图中绝大部分值都是0或者1;if a mistake is made, the algorithm leaves almost no room to express doubt.【如果训练样本中存在无间道, 将对识别结果造成很大影响】
第二个图【现有bogofilter按此实现】没有第一、三的缺点。绝大多数spam得分接近1, 绝大多数ham得分接近0, [0.1, 0.9]之间为unsure,可以在其中选择一个合适的阀值,spam_cutoff in [0.93, 0.98]
上图是比较naïve bayes(bcr, bayes chain rule), 使用fw替代pw的naïve bayes, 以及robinson-fisher的测试结果图
【使用robinson-fisher效果最好:
http://www.bgl.nu/bogofilter/BcrFisher.html
http://www.bogofilter.org/pipermail/bogofilter/2002-November/000699.html】
Bogofilter 现版本使用了robinson-fisher算法计算一封邮件属于垃圾邮件的概率
5 改进的理由/讨论
1 fw代替pw: fw包含了background info。
Pw的含义是任意一封邮件包含单词w时, 此封邮件是垃圾邮件的概率;
而fw是如下二项式分布的数学期望值:已知单词w出现了n次,在已有垃圾邮件中出现的概率是pw;那么第n+1次出现这封邮件时垃圾邮件的概率是多少【这个就是所谓的fw结合了backgroud info; 因为每次出现w时只有两种结果,垃圾邮件、非垃圾邮件; 且每次出现独立不相关的,所以符合二项式分布; fw就是上述所求概率的期望】
http://www.linuxjournal.com/article/6467
2 使用P, Q, S代替bayes chain rules
Bayes chain rules把各个词的出现看做是独立的来计算这些词同时出现时的垃圾概率【理想世界】
P, Q, S计算的是这些词combined起来计算 probability。
bogofilter基本用法
训练
bogofilter -B ../sample_mail/non_spam_test/* -n -o0.00,0.99 -k 64 -d ./wordlist
-B, 指明文件列表
-n, 表示为正常邮件
-ospam_cutoff[,hamcutoff]
-k, 指明BDB文件的大小
-d, 指明wordlist所在目录
./wordlist下的BDB文件作为内容特征输入; 训练完毕后./wordlist下的文件同时会被更新
不需要指明-u参数, 上述语句本身就是增量式训练;
bogofilter -B ../sample_mail/non_spam_test/* -Ns -o0.00,0.99 -k 64 -d ./wordlist
将已训练过的、non_spam_test下的邮件, 作为垃圾邮件重新训练。
-N, unregister non-spam
-s, register-spam
bogofilter中查看bdb文件:
bogoutil -d wordlist
bogofilter分类:
bogofilter –B path –v –ov1[,v2] –d wordlist ; 从该命令行中输出分析结果
说明
two state -o0.99,0.00: 只分两类, spam, ham
hamcutoff = 0 spamcutoff = 0.99, 得分大于0.99为垃圾邮件, 低于0.99为正常邮件
tristate -o0.99,0.8: 分三类, spam, unsure, ham
hamcutoff = 0.8 spamcutoff = 0.99, 得分大于0.99为垃圾邮件, 低于0.8为正常邮件, (0.8, 0.99)之间判定为unsure
robx 对于新词给的预定概率: 初始值为0.5,表示该词出现在垃圾邮件中的概率是0.5
robs 低于该阀值的作为新词对待
SP_ESF, effective size factor(ESF) from spam
NS_ESF, effective size factor(ESF) from nonspam
bogofilter中默认值均为1.0
垃圾邮件识别有两种错误:
False negative(fn), 将垃圾邮件识别为非垃圾邮件;漏报
False positive(fp), 将非垃圾邮件识别为垃圾邮件; 误报
bogotune 推荐参数
n=·ls nonspam | gawk {s = sprintf(“ %s –n %s”, s, $NF);}END{print s}·
Bogotune –C –d wordlist $n $s
在config file中需要指定ignore file, 包含停用词、无关词等