机器学习-朴素贝叶斯分类

xiaoxiao2021-02-28  122

今天在图书馆学习了一天,把朴素贝叶斯的基本原理给弄明白了。故写篇文章加深印象。 当然还是要推荐一发博客的:ACdreamers-朴素贝叶斯分类

一、贝叶斯定理

条件概率:

P(c|x⃗ )=P(x⃗ c)P(x⃗ ) 贝叶斯定理: P(c|x⃗ )=P(c)P(x⃗ |c)P(x⃗ ) 证明如下: P(c|x⃗ )=P(x⃗ c)P(x⃗ ) P(x⃗ |c)=P(x⃗ c)P(c) 联立两式,消去 P(x⃗ c) 得到贝叶斯定理。

二、朴素贝叶斯分类器

不难发现,基于贝叶斯定理来估计概率 P(c|x⃗ ) 的主要困难在于,类条件概率 P(x⃗ |c) 是所有属性上的联合概率,难以从有限的训练样本直接估计而得。为了避开这个障碍,朴素贝叶斯分类器采用了“属性条件独立性假设”:对已知类别,假设所有属性相互独立。

基于属性条件独立性假设,贝叶斯定理可重写为:

P(c|x⃗ )=P(c)P(x⃗ |c)P(x⃗ )=P(c)P(x⃗ )i=1dP(xi|c)

其中 d 是属性数目,xi x 在第 i 个属性上的取值。

朴素贝叶斯分类原理

对于给定待分类项,求解在此项出现的条件下,各个类别出现的概率,待分类项属于概率最大的那一类

三、使用朴素贝叶斯过滤垃圾邮件

定义事件: - c0 : 不是垃圾邮件 - c1 : 是垃圾邮件 - w⃗  : 词向量,表示一篇邮件中出现的词汇 - P(w⃗ |ci) : 在出现事件 ci 的情况下,出现的是 w⃗  的概率 - P(ci|w⃗ ) : 在出现的是词向量 w⃗  的情况下,出现的是事件 ci 的概率

由上可知,我们需要求得所有的 P(ci|w⃗ ) 并找出最大的,其事件 ci 即是分类结果

训练算法

根据朴素贝叶斯分类器:

P(ci|w⃗ )=P(ci)P(w⃗ |ci)P(w⃗ )=P(ci)P(w⃗ )j=1dP(wj|ci) 我们可以对于每个待分类的数据,已知 P(ci) P(w⃗ ) 。我们需通过训练算法得到得是 dj=1P(wj|ci)

测试算法

计算 P(ci|w⃗ ) 的值,取其中最大的,得到分类结果。与测试样本集中的结果进行比对。最后求出错误率

代码

import numpy as np import re, os, random # 将inputset转换为一个长度为len(vocabList)的列表 def setOfWord2Vec(vocabList, inputset): returnVec = [0] * len(vocabList) for word in inputset: if word in vocabList: returnVec[vocabList.index(word)] = 1 return returnVec # 读取文件filename中的所有单词,并以全部小写返回 def file2vec(filename): returnVec = [] fr = open(filename, 'r') regEx = re.compile("\W+") text = fr.read() returnVec.extend(regEx.split(text)) fr.close() return [word.lower() for word in returnVec if len(word) > 2] # 创建词汇表 def createVocabList(dataSet): returnVec = set([]) for word in dataSet: returnVec |= set(word) return list(returnVec) # 训练数据 def trainNB0(trainMatrix, trainCategory): numTrainMatrix = len(trainMatrix) numTrainWord = len(trainMatrix[0]) pAbvious = sum(trainCategory) / float(numTrainMatrix) p0Num, p1Num = np.ones(numTrainWord), np.ones(numTrainWord) p0Denom, p1Denom = 2.0, 2.0 for i in range(numTrainMatrix): # 如果是侮辱性文档,则增加p1Num if trainCategory[i] == 1: p1Num += trainMatrix[i] p1Denom += sum(trainMatrix[i]) else: p0Num += trainMatrix[i] p0Denom += sum(trainMatrix[i]) p0Vect, p1Vect = np.log(p0Num / p0Denom), np.log(p1Num / p1Denom) return p0Vect, p1Vect, pAbvious # 验证 def classifyNB(testSet, p0Vec, p1Vec, pAbvious): p0 = sum(testSet * p0Vec) + np.log(1.0 - pAbvious) p1 = sum(testSet * p1Vec) + np.log(pAbvious) if p0 > p1: return 0 else: return 1 def spamTest(): # 所有词汇集合,结果集合, docList, classList = [], [] for i in range(1, 26): wordList = file2vec("spam/%d.txt" % i) docList.append(wordList) classList.append(1) wordList = file2vec("ham/%d.txt" % i) docList.append(wordList) classList.append(0) vocabList = createVocabList(docList) trainingSet, testSet = list(range(50)), [] # 随机构造测试集 for i in range(10): randIndex = int(random.uniform(0, len(trainingSet))) testSet.append(trainingSet[randIndex]) del(trainingSet[randIndex]) trainMat, trainClasses = [], [] for docIndex in trainingSet: trainMat.append(setOfWord2Vec(vocabList, docList[docIndex])) trainClasses.append(classList[docIndex]) p0V, p1V, pSpam = trainNB0(np.array(trainMat), trainClasses) errorCount = 0 for index in testSet: word = setOfWord2Vec(vocabList, docList[index]) if classifyNB(word, p0V, p1V, pSpam) != classList[index]: errorCount += 1 print ("the error rate is:", float(errorCount) / len(docList)) if __name__ == '__main__': spamTest()

计算的时候考虑上溢出和下溢出的问题,分别做了相应的处理。具体参加《机器学习实战》4.5.3节

根据这个算法,进行了多次测试(相同数据集),因为数据集划分的是随机的,随机结果最大错误率是4%(不一定准确)

总结

优点: 在数据较少的情况下仍然有效,可以处理多类别问题 缺点: 对于输入数据的准备方式较为敏感 使用数据类型: 标称型数据

说句题外话

为什么的markdown代码块在预览的时候感觉就挺好看的…为什么发表出来之后就感觉挺难看的了….加载的样式表不一样么….

转载请注明原文地址: https://www.6miu.com/read-64097.html

最新回复(0)