对抗垃圾邮件的技术有很多,今天学习的贝叶斯算法属于一种机器学习领域的技术。这是一种分类算法,根据贝叶斯原理来计算邮件可能是垃圾邮件的概率,如果高于阈值,就认为这是垃圾邮件。其判断的准确程度随着学习次数的增加而增加,这就需要以已知的邮件作为样本进行学习,因此贝叶斯方法常会和其他垃圾邮件检测技术相配合。
贝叶斯过滤算法的基本步骤
1. 利用其他技术收集大量的垃圾邮件和非垃圾邮件,建立垃圾邮件集和非垃圾邮件集。
2. 提取邮件主题和邮件体中的独立字符串,英文可以以一个单词、中文可以以一个汉字或者词语作为TOKEN串,并统计提取出的TOKEN串出现的次数(即字频)。按照上述的方法分别处理垃圾邮件集和非垃圾邮件集中的所有邮件。
3. 两个邮件集对应两个哈希表:hashtable_good对应非垃圾邮件集,hashtable_bad对应垃圾邮件集。表中存储TOKEN串到字频的映射关系。
4. 计算每个哈希表中TOKEN串出现的概率:
P=(某TOKEN串的字频)/(对应哈希表的长度)
5. 综合考虑hashtable_good和hashtable_bad,推断出当新来的邮件中出现某个TOKEN串时,该新邮件为垃圾邮件的概率。
A事件代表邮件为垃圾邮件,t1,t2 ……tn代表TOKEN串,则 P ( A|ti )表示在邮件中出现 TOKEN 串 ti 时,该邮件为垃圾邮件的概率。
设P1 ( ti ) = ( ti 在 hashtable_good 中的值),P2 ( ti ) = ( ti 在 hashtable_ bad 中的值),由条件概率可得
P ( A|ti ) = P(A,ti)/P(ti) = P2 ( ti ) /[ ( P1 ( ti ) +P2 ( ti ) ]
6. 建立新的哈希表hashtable_probability存储TOKEN串ti到P(A|ti)的映射。
7. 至此,垃圾邮件集和非垃圾邮件集的学习过程结束。之后根据建立的哈希表 hashtable_probability可以估计一封新到的邮件为垃圾邮件的可能性。
8. 当新到一封邮件时,按照步骤2,生成TOKEN串。查询hashtable_probability得到该TOKEN 串的键值。假设由该邮件共得到N个TOKEN 串,t1,t2…….tn,hashtable_probability中对应的值为 P1 , P2 , ……PN ,
P(A|t1 ,t2, t3……tn) 表示在邮件中同时出现多个TOKEN串t1,t2……tn时,该邮件为垃圾邮件的概率。
由联合概率公式可得
P(A|t1 ,t2, t3……tn)=(P1*P2*……PN)/[P1*P2*……PN+(1-P1)*(1-P2)*……(1-PN)]
当 P(A|t1 ,t2, t3……tn) 超过预定阈值时,就可以判断邮件为垃圾邮件。
算法举例
假设有2封正常邮件e1、e2和2封垃圾邮件e3、e4,test作为测试用的邮件。我写的下面这个程序的一个缺陷就是使用一个汉字作为一个TOKEN串,而不是先采用中文分词算法以词语作为TOKEN串。所以只是作为贝叶斯算法的实现例子,实用价值并不大。
-
- from __future__ import division
- import sys
- reload(sys)
- sys.setdefaultencoding('utf8')
- exlist = ['\n',',','。','!','?','1','2','3','4','5','6','7','8','9','0']
- word = ''
- bad_file = ['e1','e2']
- good_file = ['e3','e4']
-
- for name in good_file:
- f = file(name)
- ch = f.read()
- ch = unicode(ch, 'utf-8')
- for i in range(len(ch)):
- if ch[i] in exlist:
- continue
- else:
- word += ch[i]
- f.close()
-
-
-
- good_dict = {}
- for i in range(len(word)):
- le = word[i]
- if good_dict.has_key(le):
- good_dict[le] += 1
- else:
- good_dict[le] = 1
-
-
- for k in good_dict.iterkeys():
- good_dict[k] = good_dict[k] / len(good_dict)
-
- print '####################################'
- print 'Good Email Hash:'
- for k in good_dict.iterkeys():
- print k,' : ',good_dict[k]
-
-
- word = ''
- for name in bad_file:
- f = file(name)
- ch = f.read()
- ch = unicode(ch, 'utf-8')
- for i in range(len(ch)):
- if ch[i] in exlist:
- continue
- else:
- word += ch[i]
- f.close()
-
-
-
- bad_dict = {}
- for i in range(len(word)):
- le = word[i]
- if bad_dict.has_key(le):
- bad_dict[le] += 1
- else:
- bad_dict[le] = 1
-
- for k in bad_dict.iterkeys():
- bad_dict[k] = bad_dict[k] / len(bad_dict)
-
- print '####################################'
- print 'Bad Email Hash:'
- for k in bad_dict.iterkeys():
- print k,' : ',bad_dict[k]
-
-
-
- proba = {}
- for le in bad_dict.iterkeys():
- if good_dict.has_key(le):
- proba[le] = bad_dict[le] / (bad_dict[le] + good_dict[le])
- else:
- proba[le] = 1
- print '####################################'
- print 'Probability Hash:'
- for k in proba.iterkeys():
- print k,' : ',proba[k]
-
- f = file('test')
- word = ''
- ch = f.read()
- ch = unicode(ch, 'utf-8')
- for i in range(len(ch)):
- if ch[i] in exlist:
- continue
- else:
- word += ch[i]
- f.close()
-
- pr = [ 0 for i in range(len(word)) ]
- j = 0
- for i in range(len(word)):
- if proba.has_key(word[i]):
- pr[j] = proba[word[i]]
- else:
- pr[j] = 0
- j = j + 1
-
- p1 = 1
- p2 = 1
- for i in range(len(pr)):
- p1 = p1 * pr[i]
- p2 = p2 * (1 - pr[i])
-
- probability = p1 / (p1 + p2)
- print '########################################'
- print 'probability: ',probability