Bayes 朴素贝叶斯实现垃圾邮件分类
Posted 野鹿的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bayes 朴素贝叶斯实现垃圾邮件分类相关的知识,希望对你有一定的参考价值。
本文选取了25封垃圾邮件和25封正常邮件,随机产生了10组测试集和40组训练集,使用朴素贝叶斯方法实现了垃圾邮件的分类。
Bayes公式
遍历每篇文档向量,扫描所有文档的单词,合并集合去重 ,并生成最终的词汇表
# 创建词汇表
# 输入:dataSet已经经过切分处理
# 输出:包含所有文档中出现的不重复词的列表
def createVocabList(dataSet): # 文本去重,创建词汇表
vocabSet = set([]) # 创建一个空的集合
for document in dataSet: # 遍历每篇文档向量,扫描所有文档的单词
vocabSet = vocabSet | set(document) # 合并集合,并生成最终的词汇表
return list(vocabSet)
查找关键词语并标记
# ***词集模型:只考虑单词是否出现
# vocabList:词汇表
# inputSet :某个文档向量
def setOfWords2Vec(vocabList, inputSet): # 查找词语并标记
returnVec = [0] * len(vocabList) # 初始化一个和单词等长集合,初始化为0
# 依次取出文档中的单词与词汇表进行对照,若在词汇表中出现则为1
for word in inputSet:
if word in vocabList:
# 单词在词汇表中出现,则记为1
returnVec[vocabList.index(word)] = 1 # vocabList.index(word)下标
# 若测试文档的单词,不在词汇表中,显示提示信息,该单词出现次数用0表示
else:
print("the word: %s is not in my Vocabulary!" % word)
return returnVec
原始的朴素贝叶斯源码
# P(ci|w)=(P(w|ci) P(ci))/(P(w)) 词向量的贝叶斯准则
# P(w0,w1,w2,w3..|ci) ==p(w0|ci) P(w1|ci) ....
# 1.计算每个类别中的文档数目
# 2.针对每篇训练文档:
# 对每个类别:
# 如果词条出现在文档中--〉增加该词条的记数值
# 增加所有词条的记数值
# 对每个类别:
# 对每个词条:
# 将该词条的数目除以总词条书得到条件概率
# 返回每个类别的条件概率
# ====训练分类器,原始的朴素贝叶斯,没有优化=====
# 输入trainMatrix:词向量数据集
# 输入trainCategory:数据集对应的类别标签
# 输出p0Vect:词汇表中各个单词在正常言论中的类条件概率密度
# 输出p1Vect:词汇表中各个单词在侮辱性言论中的类条件概率密度
# 输出pAbusive:侮辱性言论在整个数据集中的比例
def trainNB0(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix) # numTrainDocs训练集总条数
numWords = len(trainMatrix[0]) # 训练集中所有不重复单词总数
pAbusive = sum(trainCategory) / float(numTrainDocs) # 侮辱类的概率(侮辱类占总训练数据的比例)
# 初始化概率
p0Num = ones(numWords) # *正常言论的类条件概率密度 p(某单词|正常言论)=p0Num/p0Denom
p1Num = ones(numWords) # *侮辱性言论的类条件概率密度 p(某单词|侮辱性言论)=p1Num/p1Denom
p0Denom = 0.0 # 初始化分母置为0
p1Denom = 0.0
for i in range(numTrainDocs): # 遍历训练集数据
if trainCategory[i] == 1: # 若为侮辱类
p1Num += trainMatrix[i] # 统计侮辱类所有文档中的各个单词总数
p1Denom += sum(trainMatrix[i]) # p1Denom侮辱类总单词数
else: # 若为正常类
p0Num += trainMatrix[i] # 统计正常类所有文档中的各个单词总数
p0Denom += sum(trainMatrix[i]) # p0Denom正常类总单词数
# 对每个元素作除法
p1Vect = p1Num / p1Denom
p0Vect = p0Num / p0Denom
return p0Vect, p1Vect, pAbusive
文档分类,统计词频,切分词和大小写转换
# vec2Classify:待分类文档
# p0Vect:词汇表中每个单词在训练样本的正常言论中的类条件概率密度
# p1Vect:词汇表中每个单词在训练样本的侮辱性言论中的类条件概率密度
# pClass1:侮辱性言论在训练集中所占的比例
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
# 在对数空间中进行计算,属于哪一类的概率比较大就判为哪一类
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
# ***词袋模型:考虑单词出现的次数
# vocabList:词汇表
# inputSet :某个文档向量
def bagOfwrods2VecMN(vocabList, inputSet):
# 创建所含元素全为0的向量
returnVec = [0] * len(vocabList)
# 依次取出文档中的单词与词汇表进行对照,统计单词在文档中出现的次数
for word in inputSet:
if word in vocabList:
# 单词在文档中出现的次数
returnVec[vocabList.index(word)] += 1
return returnVec
# 准备数据,按空格切分出词
# 单词长度小于或等于2的全部丢弃
def textParse(bigString):
import re
listOfTokens = re.split(r"\\W*", bigString)
# tok.lower() 将整个词转换为小写
return [tok.lower() for tok in listOfTokens if len(tok) > 0]
spamTest 在50封邮件中选取10篇邮件随机选择为测试集交叉验证。
# 读出邮件,并进行训练和测试
def spamTest():
docList = [] # 文章按篇存放
classList = [] # 存放文章类别
fullText = [] # 存放所有文章内容
# 读文档
for i in range(1, 26):
# 读取垃圾邮件
wordList = textParse(open("email\\spam\\%d.txt" % i).read())
docList.append(wordList) # docList按篇存放文章
fullText.extend(wordList) # fullText邮件内容存放到一起
classList.append(1) # 垃圾邮件类别标记为1
# 读取正常邮件
wordList = textParse(open("email\\ham\\%d.txt" % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
# 随机构建训练集
vocabList = createVocabList(docList) # 创建词典
trainingSet = list(range(50)) # 训练集共50篇文章
testSet = [] # 创建测试集
# 随机选取10篇文章为测试集,测试集中文章从训练集中删除
for i in range(20):
# 0-50间产生一个随机数
randIndex = int(random.uniform(0, len(trainingSet)))
# 从训练集中找到对应文章,加入测试集中
testSet.append(trainingSet[randIndex])
# 删除对应文章
del (trainingSet[randIndex])
# 准备数据,用于训练分类器
trainMat = [] # 训练数据
trainClasses = [] # 类别标签
for docIndex in trainingSet: # 遍历训练集中文章数据
# 每篇文章转为词袋向量模型,存入trainMat数据矩阵中
trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))
# trainClasses存放每篇文章的类别
trainClasses.append(classList[docIndex])
# 训练分类器
p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))
# errorCount记录测试数据出错次数
errorCount = 0
# 遍历测试数据集,每条数据相当于一条文本
for docIndex in testSet:
# 文本转换为词向量模型
wordVector = setOfWords2Vec(vocabList, docList[docIndex])
# 模型给出的分类结果与本身类别不一致时,说明模型出错,errorCount数加1
if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
errorCount += 1
# 输出出错的文章
print("出错的文章", docList[docIndex])
print("实际分类", classList[docIndex])
print("预测分类", classifyNB(array(wordVector), p0V, p1V, pSpam))
print(\'错误率 : \', float(errorCount) / len(testSet))
结果
出错的文章 [\'a\', \'home\', \'based\', \'business\', \'opportunity\', \'is\', \'knocking\', \'at\', \'your\', \'door\', \'don抰\', \'be\', \'rude\', \'and\', \'let\', \'this\', \'chance\', \'go\', \'by\', \'you\', \'can\', \'earn\', \'a\', \'great\', \'income\', \'and\', \'find\', \'your\', \'financial\', \'life\', \'transformed\', \'learn\', \'more\', \'here\', \'to\', \'your\', \'success\', \'work\', \'from\', \'home\', \'finder\', \'experts\']
实际分类 1
预测分类 0
错误率 : 0.05
由于取的是随机数,错误识别大部分情况下都很高,朴素贝叶斯的分母忽略和训练集过少是主要原因。
以上是关于Bayes 朴素贝叶斯实现垃圾邮件分类的主要内容,如果未能解决你的问题,请参考以下文章