失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 朴素贝叶斯分类算法分析与实践

朴素贝叶斯分类算法分析与实践

时间:2022-10-16 01:02:04

相关推荐

朴素贝叶斯分类算法分析与实践

1.分析

1.1 背景意义:

KNN和分类决策树都是要求分类器能够给出实例明确属于哪一类?但很多时候我们没法判断准确是哪一类时候,这时候起码能够给出最优可能的那一类和有多大概率属于该类。朴素贝叶斯分类算法就可以干这事。

1.2 原理

首先概述整个朴素贝叶斯分类算法:对于给定的训练数据集,首先基于“特征条件独立假设”学习输入输出的联合概率分布;然后基于此模型,对于给定的输入(实例),利用贝叶斯定理求出后验概率最大的输出(类别)。

所以,我们的目标是,根据样本,算出该样本属于每个类别的后验概率,比较得出最大值对应的那个就是最有可能的类别,由贝叶斯定理有公式如下:

由于条件概率难算:是一个d维向量,那么就有d次方的指数级别种可能的组合,远大于样本的数量,说明一些组合是没有的,因此用样本出现的频数来估计条件概率既难算又不合理。所以用到了“特征条件独立假设”,该假设是说,用来分类的特征,在类确定的条件下是条件独立的,就是说每个特征对分类的影响独立。这是一个较强的假设(因为特征之间可能有关联性),使得该分类方法变得简单,损失一定准确性,所以称之为"朴素"。

由“特征条件独立假设”有公式如下:

并且由于对于每一个类别都是一样的,所以朴素贝叶斯分类器的表达式为:

参数估计用极大似然估计,其实也就是用频数来代表概率。

算法流程如下:

图来源于/p/36545000

直接使用极大似然估计法时,需要注意,若某个属性值在训练集中没有与某个类同时出现,则直接基于之前的公式进行概率估计,再进行判别将出现问题。不能因为没有出现该样本,而直接把该样本的出现概率设为0。为了避免其他属性携带的信息被训练集中未出现的属性值 “抹去”,在估计概率值时通常需要进行 “平滑” (smoothing),我们常用“拉普拉斯修正”。公式具体看李航书P51。

2.实践(《机器学习实战》第四章代码解析)

使用python来文本分类

1.准备数据:从文中构建词向量

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']]#0-非侮辱性,1-侮辱性classVec = [0,1,0,1,0,1] return postingList,classVecdef createVocabList(dataset):#获取词汇表:把文本集装换成一个不含重复词的列表vocabSet = set([])#创建一个空集,可以进行集合操作for document in dataset:vocabSet = vocabSet |set(document)#每次把文件中的不重复元素放入return list(vocabSet)def setOfWords2Vec(vocabList, inputSet):#转化成向量:参数是词汇表和某个文档returnVec = [0]*len(vocabList)#构建vocabList长度的0向量for word in inputSet: #把该文档中在词汇表中有该单词的位置标位1(one-hot向量)if word in vocabList:returnVec[vocabList.index(word)]=1 else:print("the word: %s is not in my Vocabulary!" % word)return returnVec

2.训练算法:从词向量计算概率

def trainNB0(trainMatrix, trainGategory):numTrainDocs = len(trainMatrix) #返回训练的文档数目numWords = len(trainMatrix[0]) #返回每一篇文档的词条数pAbusive = sum(trainGategory)/float(numTrainDocs) #文档属于侮辱类的概率#用拉普拉斯修正”来平滑数据p0Num = np.ones(numWords); p1Num = np.ones(numWords) #创建numpy.zeros数组,词条出现数初始化为0p0Denom = 2.0; p1Denom = 2.0 #分母初始化为2for i in range(numTrainDocs):if trainGategory[i] == 1: #统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···p1Num += trainMatrix[i]p1Denom += sum(trainMatrix[i])else: #统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···p0Num += trainMatrix[i]p0Denom += sum(trainMatrix[i])p1Vect = np.log(p1Num/p1Denom)#log防止下溢出p0Vect = np.log(p0Num/p0Denom)return p0Vect,p1Vect,pAbusive #返回属于非侮辱类的条件概率数组,属于侮辱类的条件概率数组,文档属于侮辱类的概率

3.测试算法:根据现实情况修改分类器

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):p1 = sum(vec2Classify*p1Vec)+np.log(pClass1)# #对应元素相乘。logA * B = logA + logB,所以这里加上log(pClass1)p0 = sum(vec2Classify*p0Vec)+np.log(1.0-pClass1)if p1 > p0:return 1else:return 0def testingNB():listOPosts,listClasses = loadDataSet()myVocabList = createVocabList(listOPosts)trainMat = []for postinDoc in listOPosts:trainMat.append(setOfWords2Vec(myVocabList, postinDoc))p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))testEntry = ['love','my','dalmation']thisDoc = np.array(setOfWords2Vec(myVocabList,testEntry))print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))testEntry = ['stupid','garbage']thisDoc = np.array(setOfWords2Vec(myVocabList,testEntry))print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))

4.准备数据:文档词袋模型:和setOfWords2Vec区别是每个单词可以重复多次

#词袋模型def bagOfWords2VecMN(vocabList, inputSet):returnVec = [0]*len(vocabList)for word in inputSet:if word in vocabList:returnVec[vocabList.index(word)] += 1return returnVec

示例:使用朴素贝叶斯过滤垃圾邮件

def textParse(bigString):"""输入很长的字符串,转换为向量参数:bigString -- 长字符串返回:去掉少于两个字符,转换为小写的字符串"""import relistOfTokens = re.split(r'\W*', bigString)#正则表达式来去掉空格和标点符号return [tok.lower() for tok in listOfTokens if len(tok) > 2] #全变成小写,去掉少于两个字符的字符串def spamTest():#新建三个列表docList=[]; classList = []; fullText =[]#遍历垃圾邮件和正常邮件,各25个for i in range(1,26):#读取垃圾邮件wordList = textParse(open("email/spam/{}.txt".format(i), errors = 'ignore').read())#添加到列表docList.append(wordList)fullText.extend(wordList)#添加到类classList.append(1)#读取正常邮件#ham中的23.txt总是报错有不能解读的字节,选择忽略该错误wordList = textParse(open("email/ham/{}.txt".format(i), errors = 'ignore').read())docList.append(wordList)fullText.extend(wordList)classList.append(0)#创建词汇表vocabList = createVocabList(docList)#训练集和测试集序号集trainingSet = list(range(50)); testSet=[]#随机抽取训练集中的10个序号,放入测试集for i in range(10):#生成随机序号randIndex = np.int(np.random.uniform(0,len(trainingSet)))#序号对应的元素由训练集移动到测试集中testSet.append(trainingSet[randIndex])del(trainingSet[randIndex]) #新建训练矩阵和训练标签trainMat=[]; trainClasses = []#对于训练集中的元素for docIndex in trainingSet:#对应词袋添加到训练矩阵中trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))#类别添加到标签中trainClasses.append(classList[docIndex])#训练朴素贝叶斯分类器p0V,p1V,pSpam = trainNB0(np.array(trainMat),np.array(trainClasses))#错误计数器初始化为0errorCount = 0#对于测试集for docIndex in testSet:#得到词袋向量wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])#判断结果if classifyNB(np.array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:#统计错误errorCount += 1#打印错误信息print("错误序号为:{}".format(docList[docIndex]))print("总准确率为:{}".format(1 - np.float(errorCount)/len(testSet)))

参考

【1】/p/36545000

【2】《统计学习方法》李航

【3】《机器学习实战》

如果觉得《朴素贝叶斯分类算法分析与实践》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。