关于朴素贝叶斯的理论介绍,请参见下方链接:
带你搞懂朴素贝叶斯分类算法
python代码实现朴素贝叶斯分类算法
'''判断留言是否属于敏感类留言'''
import numpy as np
def loadDataSet():#生成一个文本集
postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
classVec = [0,1,0,1,0,1] #0代表正常留言,1代表敏感留言
return postingList,classVec
def createVocabList(dataSet):#利用文本集,生成一个词汇表
vocabSet = set() #确保词汇表的唯一性
for document in dataSet:
vocabSet = vocabSet | set(document)
return list(vocabSet)
def setofwordsvec(vocabList,inputSet):#检查句中的单词是否在词汇表里存在
#(词集模型,即只判断该词是否出现)
returnvec = [0]*len(vocabList) #依据词汇表的长度生成一个全为0的向量
for word in inputSet:
if word in vocabList:
returnvec[vocabList.index(word)] = 1 #如果单词存在词汇表,则将词汇表
#对应的值设为1
else:
print('the word:{}is not in my vocabulary'.format(word))
return returnvec
def bagofwordsvec(vocabList,inputSet):#检查句中的单词是否在词汇表里存在
#(词袋模型,统计每个词出现的次数)
returnvec = [0]*len(vocabList) #依据词汇表的长度生成一个全为0的向量
for word in inputSet:
if word in vocabList:
returnvec[vocabList.index(word)] += 1 #如果单词存在词汇表,则将词汇表
#对应的值加1
else:
print('the word:{}is not in my vocabulary'.format(word))
return returnvec
#朴素贝叶斯分类器通常有两种实现方式,一种基于贝努利模型实现,一种基于多项式模型实现
#贝努利模型不考虑词出现的次数,只考虑词出不出现,相当于每个词的权重都是一样的
#多项式模型考虑词出现的次数,即给词赋予不一样的权重
listOposts,listclasses = loadDataSet()
myvocablist = createVocabList(listOposts)
'''初版
def trainNBO(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) #获取有多少条文本
numWords = len(trainMatrix[0]) #获取文本长度
pAbusive = np.sum(trainCategory)/float(numTrainDocs)#带有敏感字的文档和是3,
#除以总文档数,即为是敏感文档的概率p(1)
p0Num = np.zeros(numWords)#根据文本长度设定一个全0向量
p1Num = np.zeros(numWords)#这里注意,生成的类型是np.ndarray
p0Denom = 0
p1Denom = 0
for i in range(numTrainDocs):#遍历所有文本
if trainCategory[i] == 1:#如果对应的标签是1,即敏感文本
p1Num += trainMatrix[i] #统计文本中所有单词出现的次数
#因为类型是np.ndarray,所以这里对应位置的值是直接相加的
p1Denom += np.sum(trainMatrix[i]) #这里统计共有多少词
else:#因为此例只有两个特征,即0或1,所以if后可直接else,否则要多加判断,
#且要新增对应的统计变量
p0Num += trainMatrix[i]
p0Denom += np.sum(trainMatrix[i])
p1Vect = p1Num/p1Denom #这里计算敏感文本中,每个词占该类型下所有词的比例,即p(wi|c1)
p0Vect = p0Num/p0Denom #这是p(wi|c0) #i和0是下标
return p0Vect,p1Vect,pAbusive
'''
#根据朴素贝叶斯假设,p(w|c) = p(w1|c)p(w2|c)...p(wn|c),因此我们要避免其中一项为0
#所以上述代码中,p0Num及p1Num的定义我们改为np.ones(numWords),同时将p0Denom和p1Denom初始化为2
#关于p0Vect和p1Vect的定义中,当因子非常小时,该变量值也小,那么p(w|c) = p(w1|c)p(w2|c)...p(wn|c)
#就很有可能下溢或者得不到正确答案,这里我们将其采用自然对数进行处理。改为:p1Vext = np.log(p1Num/p1Denom)
#f(x)和ln(f(x))在趋势上一致
'''优化后'''
def trainNBO(trainMatrix,trainCategory):#计算各类文档概率以及各种词出现在各类文档的概率
numTrainDocs = len(trainMatrix) #获取有多少条文本
numWords = len(trainMatrix[0]) #获取文本长度
pAbusive = np.sum(trainCategory)/float(numTrainDocs)#带有敏感字的文档和是3,
#除以总文档数,即为是敏感文档的概率p(1)
p0Num = np.ones(numWords)#根据文本长度设定一个全0向量
p1Num = np.ones(numWords)#这里注意,生成的类型是np.ndarray
p0Denom = 0
p1Denom = 0
for i in range(numTrainDocs):#遍历所有文本
if trainCategory[i] == 1:#如果对应的标签是1,即敏感文本
p1Num += trainMatrix[i] #统计文本中所有单词出现的次数
#因为类型是np.ndarray,所以这里对应位置的值是直接相加的
p1Denom += np.sum(trainMatrix[i]) #这里统计共有多少词
else:#因为此例只有两个特征,即0或1,所以if后可直接else,否则要多加判断,
#且要新增对应的统计变量
p0Num += trainMatrix[i]
p0Denom += np.sum(trainMatrix[i])
p1Vect = log(p1Num/p1Denom) #这里计算敏感文本中,每个词占该类型下所有词的比例,即p(wi|c1)
p0Vect = log(p0Num/p0Denom) #这是p(wi|c0) #i和0是下标
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):#计算最终概率并对比
p1 = np.sum(vec2Classify*p1Vec) + np.log(pClass1)#因为转成log了,所以原定理中
#相乘的部分通过相加实现,另外定理中还有一个分母,这里也没用,是因为要对比的分母是一样的
#因此,这里只对比分子
p0 = np.sum(vec2Classify*p0Vec) + np.log(1-pClass1)
if p1 > p0:
return 1
else:
return 0
def testingNB():#定义测试函数
listOPosts,listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setofwordsvec(myVocabList,postinDoc))
p0V,p1V,pAb = trainNBO(np.array(trainMat),np.array(listClasses))
testEntry = ['love','my','dalmation']
thisDoc = np.array(setofwordsvec(myVocabList,testEntry))
print(testEntry,'classified as :',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry = ['stupid','garbage']
thisDoc = np.array(setofwordsvec(myVocabList,testEntry))
print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))
示例:使用朴素贝叶斯过滤垃圾邮件
import re
def textParse(bigString):#定义一个规整化邮件文本函数
listoftokens = re.split(r'\W*',bigString)#将字符串进行分割
return [tok.lower() for tok in listoftokens if len(tok)>2] #将分割后的词汇全部转为小写,
#并排除长度小于2的词
def spamTest():
doclist = []
classlist = []
fulltext = []
for i in range(1,26):#打开所有邮件样本,并汇总其中的文本及词汇
emailText = open('D:/Anaconda/test/机器学习/Ch04/email/spam/{}.txt'.format(i),encoding='gbk').read()
wordlist = textParse(emailText)
doclist.append(wordlist)
fulltext.extend(wordlist)
classlist.append(1)
emailText = open('D:/Anaconda/test/机器学习/Ch04/email/ham/{}.txt'.format(i),encoding='gbk').read()
wordlist = textParse(emailText)
doclist.append(wordlist)
fulltext.extend(wordlist)
classlist.append(0)
vocablist = createVocabList(doclist)#建立词汇集
trainingSet = list(range(50))#总文档数是50
testSet = []
for i in range(10):#随机抽取10个文档作为测试集
randIndex = int(np.random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del trainingSet[randIndex]
trainMat = []
trainClasses = []
for docIndex in trainingSet:#剩下的40个文档为训练集
trainMat.append(setofwordsvec(vocablist,doclist[docIndex]))
#将剩下40个文档转化为向量后放入trainMat列表中
trainClasses.append(classlist[docIndex])#将剩下40个文档的对应类型放到trainClasses列表中
p0V,p1V,pSpam = trainNBO(np.array(trainMat),np.array(trainClasses))
#计算概率
errorCount = 0
for docIndex in testSet:#利用测试集中的文档验证错误率
wordVector = setofwordsvec(vocablist,doclist[docIndex])
if classifyNB(np.array(wordVector),p0V,p1V,pSpam) != classlist[docIndex]:
errorCount += 1
print('the error rate is :',float(errorCount)/len(testSet))
#随机选择一部分作为训练集,二剩余部分作为测试集的过程称为留存交叉验证