基于朴素贝叶斯分类算法的邮件过滤系统
前言
朴素贝叶斯算法最为广泛而经典的应用毫无疑问是文档分类,更具体的情形是邮件过滤系统。
本文详细地讲解一个基于朴素贝叶斯分类算法的邮件过滤系统的具体实现。
本文侧重于工程实现,至于其中很多算法的细节请参考之前的一篇文章:朴素贝叶斯分类算法原理分析与代码实现。
准备数据:切分文本
获取到文本文件之后,首先要做的是两件事情:
1. 将文本文件转换为词汇列表
2. 将上一步的结果进一步转换为词向量
对于 1,具体来说,就是将文本文件以非字母或数字之外的字符为界进行切割。
仅仅使用字符串的 split 函数实现起来很麻烦,而Python中真正处理文本的利器是正则表达式,使用正则表达式可轻易实现这个任务。
如下函数可用于实现1:
1 #============================================= 2 # 输入: 3 # bigString: 待转换文档字符串 4 # 输出: 5 # 待转换文档的列表格式 6 #============================================= 7 def textParse(bigString): 8 import re 9 listOfTokens = re.split(r'\W*', bigString) 10 return [tok.lower() for tok in listOfTokens if len(tok) > 2]
注意,由于切分后的结果有可能出现空格符,因此在返回时再加了一层过滤。
关于正则表达式的具体用法不属于本文讲解范围,有兴趣的读者请自行查阅相关资料。
对于2,在上一篇文章:朴素贝叶斯分类算法原理分析与代码实现中已经有过实现的范例,这里就不再累述。
训练并测试
1. 从代码中指定路径的目录中查找邮件(不同分类的两个目录),搜集所有邮件信息并将其转换为词向量格式。
2. 将这部分数据再分为训练集部分和测试集部分。
3. 调用朴素贝叶斯分类函数对数据集进行训练,得到贝叶斯公式中的各个概率子项。
4. 求出待分类文档的词向量并继续完成此贝叶斯公式来计算该词向量的属于各分类的概率。取其中最大概率为分类结果。
5. 将上一步得到的分类结果和实际结果对照,打印最终测试信息。
如下代码用于训练及测试:
1 #============================================= 2 # 输入: 3 # vocabList: 词汇列表 4 # inputSet: 待转换文档的列表格式 5 # 输出: 6 # returnVec: 转换后的词向量(词袋模型) 7 #============================================= 8 def bagOfWords2VecMN(vocabList, inputSet): 9 '文档(列表格式) -> 词向量(词袋模型)' 10 11 returnVec = [0]*len(vocabList) 12 for word in inputSet: 13 if word in vocabList: 14 returnVec[vocabList.index(word)] += 1 15 16 return returnVec 17 18 #============================================= 19 # 输入: 20 # 代码内指定路径的两种分类邮件 21 # 输出: 22 # 空 (打印贝叶斯分类测试的结果) 23 #============================================= 24 def spamTest(): 25 '测试贝叶斯分类并打印结果' 26 27 # 文档字符串集合 28 docList=[] 29 # 文档分类集合 30 classList = [] 31 # 所有字符串 32 fullText =[] 33 34 # 从两种分类邮件中各取出25封邮件,获得文档字符串集合,文档分类集合,所有字符串。 35 for i in range(1,26): 36 wordList = textParse(open('/home/fangmeng/email/spam/%d.txt' % i).read()) 37 docList.append(wordList) 38 fullText.extend(wordList) 39 classList.append(1) 40 wordList = textParse(open('/home/fangmeng/email/ham/%d.txt' % i).read()) 41 docList.append(wordList) 42 fullText.extend(wordList) 43 classList.append(0) 44 45 # 词汇表 46 vocabList = createVocabList(docList) 47 # 训练集范围 48 trainingSet = range(50) 49 # 测试集范围 50 testSet=[] 51 52 # 这总共50封邮件里,取10封用来做分类测试。 53 # 同时将这10封测试邮件从训练集范围内移除。 54 for i in range(10): 55 randIndex = int(random.uniform(0,len(trainingSet))) 56 testSet.append(trainingSet[randIndex]) 57 del(trainingSet[randIndex]) 58 59 # 训练集词向量矩阵 60 trainMat=[] 61 # 训练集分类列表 62 trainClasses = [] 63 64 # 构建训练集词向量矩阵和训练集分类列表 65 for docIndex in trainingSet: 66 trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex])) 67 trainClasses.append(classList[docIndex]) 68 69 # 对训练集中邮件进行分类测试并打印测试结果 70 p0V,p1V,pSpam = trainNB0(numpy.array(trainMat),numpy.array(trainClasses)) 71 errorCount = 0 72 for docIndex in testSet: 73 wordVector = bagOfWords2VecMN(vocabList, docList[docIndex]) 74 if classifyNB(numpy.array(wordVector),p0V,p1V,pSpam) != classList[docIndex]: 75 errorCount += 1 76 print "错误分类:\n",docList[docIndex] 77 print '错误率: \n',float(errorCount)/len(testSet)
打印结果大致如下(测试集为随机选取,故每次执行可能不同):
小结
1. 文档解析在具体的文档分类项目中占有很大比重。完美的文档解析可通过正则表达式达到。
2. 在项目实现时,尽可能使用Python的一些工具(如正则表达式),或者第三方库(如numpy),能很大程度提高开发效率。