贝叶斯公式基于条件独立,经过条件几率公式和全几率公式推导而来。python
条件独立的公式以下,其含义是当C发生时,A、B的发生互不干扰。
P(A∩B|C)=P(A|C)∩P(B|C)<=>P(A|B,C)=P(A|C)<=>A,B对于C是条件独立的正则表达式
P(A|B)=P(AB)/P(B)
变形公式:P(AB)=P(A|B)·P(B)=P(B|A)·P(A)算法
若是事件B一、B二、B3…Bn 构成一个完备事件组,即它们两两互不相容,其和为全集;而且P(Bi)大于0,则对任一事件A有
P(A)=P(A|B1)P(B1) + P(A|B2)P(B2) + ... + P(A|Bn)P(Bn)。
或者:p(A)=P(AB1)+P(AB2)+...+P(ABn)(其中A与Bn的关系为交)app
贝叶斯定义用来描述两个条件几率之间的关系,好比 P(A|B) 和 P(B|A)。下面是贝叶斯公式推导过程,其中①②③都是贝叶斯公式的变形。dom
贝叶斯分类是一类以贝叶斯定理为基础的分类算法的总称,朴素贝叶斯分类是其中之一,这里的“朴素”指各个特征之间是相互独立、互不影响的。主要应用于:求已知一些特征函数,求其属于某一类别的几率。
P(类别|特征1,特征2,特征3...)=P(特征1,特征2,特征3...|类别)·P(类别)/P(特征1,特征2,特征3...)
假设各个特征相互独立,则:
P(类别|特征1,特征2,特征3...)=P(特征1,特征2,特征3...|类别)·P(类别)/[P(特征1)·P(特征2)·P(特征3)·...]ide
咱们想知道考试前一天逛街、刷视频、玩游戏、学习对成绩的影响。设:成绩优秀为1,成绩差为0;考试前一天逛街了为1,没有为0;考试前一天刷视频了为1,没有为0;考试前一天玩游戏了为1,没有为0;考试前一天学习了为1,没有为0。现有以下样本库:函数
成绩 | 逛街 | 刷视频 | 玩游戏 | |
① | 0 | 1 | 1 | 1 |
② | 0 | 1 | 0 | 1 |
③ | 1 | 0 | 0 | 0 |
④ | 0 | 0 | 0 | 0 |
⑤ | 1 | 0 | 0 | 1 |
⑥ | 0 | 0 | 1 | 1 |
⑦ | 0 | 1 | 0 | 0 |
⑧ | 1 | 1 | 0 | 1 |
⑨ | 0 | 1 | 0 | 1 |
⑩ | 0 | 1 | 0 | 1 |
求考试前一天逛街了,玩游戏了,没有刷视频、学习,成绩优秀的几率是多少?
P(1|1,0,1,0)
=P(1,1,0,1,0)/[P(逛街=1)·P(刷视频=0)·P(玩游戏=1)·P(学习=0)]
=0.1/(0.6 * 0.8 * 0.7 * 0.7)
=0.4252学习
咱们再来算一下成绩差的几率为多少
P(0|1,0,1,0)
=P(0,1,0,1,0)/[P(逛街=1)·P(刷视频=0)·P(玩游戏=1)·P(学习=0)]
=0.2/(0.6 * 0.8 * 0.7 * 0.7)
=0.8503测试
经过上面的计算,咱们发现两个几率之和并不等于1。实际上在朴素贝叶斯分类器中,经过比较两个几率大小,判断属于哪一个类别。因为分母时同样的,咱们一般省去分母,只比较分子。spa
拉普拉斯平滑主要处理零几率问题,就是在计算实例的几率时,若是某个量x,在观察样本库(训练集)中没有出现过,会致使整个实例的几率结果是0。在文本分类的问题中,当一个词语没有在训练样本中出现,该词语调几率为0,使用连乘计算文本出现几率时也为0。这是不合理的,不能由于一个事件没有观察到就武断的认为该事件的几率是0。
为了解决零几率的问题,法国数学家拉普拉斯最先提出用加1的方法估计没有出现过的现象的几率,因此加法平滑也叫作拉普拉斯平滑。假定训练样本很大时,每一个份量x的计数加1形成的估计几率变化能够忽略不计,但能够方便有效的避免零几率问题。
(1)
朴素贝叶斯根据先验几率(特征的可能性分布)有三种模型:高斯贝叶斯、伯努利贝叶斯、多项式贝叶斯。这三个类适用的分类场景各不相同,通常来讲,若是样本特征的分布大部分是连续值,使用GaussianNB会比较好。若是样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适。而若是样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。
sklearn 库中的 naive_bayes 模块实现了 5 种朴素贝叶斯算法:高斯贝叶斯、伯努利贝叶斯、多项式贝叶斯、分类贝叶斯、补充贝叶斯。
后缀NB是朴素贝叶斯(Naive Bayes)的缩写
Accuray表示测试集的准确率,cv=10表示十折交叉验证
下面代码举了三种朴素贝叶斯分类,若是想看高斯朴素贝叶斯,把前三行代码高斯朴素贝叶斯取消注释,另两个注释,并将qnb=MultinomialNB()改成qnb=GaussianNB()。
#from sklearn.naive_bayes import GaussianNB#高斯分布下的朴素贝叶斯分类 #from sklearn.naive_bayes import BernoulliNB#驳伯努利分布 from sklearn.naive_bayes import MultinomialNB#多项分布 from sklearn.model_selection import cross_val_score from sklearn import datasets iris=datasets.load_iris() print(iris) qnb=MultinomialNB() scores=cross_val_score(qnb,iris.data,iris.target,cv=10,scoring='accuracy') print('Accuracy:%.3f'%scores.mean())
若没有安装sklearn包,在终端输入pip install sklearn便可。
cd C:\Users\WAFF\AppData\Local\Programs\Python\Python37\Scripts
pip install sklearn
(2)k折交叉验证
数据集包括训练集和测试集,咱们通常用准确率Auc,即分类正确的样本个数占总样本的比例,来评价分类器的好坏。
k折交叉验证,指将数据集分K个部分(K个格子):红色为测试集test,橙色为训练集train,每次划分都有一个准确率Auci,取其平均值为最终的准率率。
垃圾邮件分类器,功能是将邮件样本集中垃圾邮件分类出来。以英文邮件为例,主要步骤为:
(1)查看数据data:邮件内容
(2)分词:句子->单词,以空格为标识
(3)向量化:单词->数字->二进制
(4)朴素贝叶斯公式:P(类别|单词1,单词2,单词3,...)=P(单词i|类别)*P(类别)/P(单词i)
(5)结果
代码中解释很是详细
#朴素贝叶斯分类器训练函数 # def trainNB0(trainMatrix,trainCategory): #总文件数 numTrainDocs=len(trainMatrix) #总单词数 numWords=len(trainMatrix[0]) #侮辱性文件出现几率 pAbusive=sum(trainCategory)/float(numTrainDocs) #构造单词出现次数列表 #p0Num正确的统计 #p1Num侮辱的统计 p0Num=np.ones(numWords) p1Num=np.ones(numWords) #整个数据集单词出现的总数,根据样本/实际调查结果调整分母的值 global p0Denom global p1Denom p0Denom=2.0 p1Denom=2.0 for i in range(numTrainDocs): if trainCategory[i]==1; #累加辱骂词的频次 p1Num+=trainMatrix[i] #对每篇文章的辱骂的频次 进行统计汇总 p1Denom+=sum(trainMatrix[i]) else: p0Num+=trainMatrix[i] p0Denom+=sum(trainMatrix[i]) #类别1 即侮辱性文档的[log(F1/C1),log(F2/C2),log(F3/C3)...]避免0的产生,拉普拉斯平滑的一种方法取log? p1Vect=np.log(p1Num/p1Denom) #类别0 即正常文档的[log(F0/C0),log(F0/C0),log(F0/C0)...] p0Vect=np.log(p0Num/p0Denom) return p0Vect,p1Vect,pAbusive #切分文本 def textParse(bigString) ''' Desc: 接收一个大字符串并将其解析为字符串列表 Args: bigString--大字符串 jieba 中文切分,本身查 Returns: 去掉少于2个字符的字符串,并将全部字符串转换为小写,返回字符串列表 ''' import re #使用正则表达式来切分句子,其中分隔符是除单词、数字外的任意字符串 list0fTokens=re.split(r'\w*',bigString) return [tok.lower() for tok in list0fTokens if len(tok)>2] def createVocabList(dataSet) ''' 获取全部单词的集合 :param dataSet:数据集 :return:全部单词的集合(即不含重复元素的列表) ''' vocabSet=set([])#creat empty set for document in dataSet: #操做符|用于求两个集合的并集 vocabSet=vocabSet|set(document)#union of the two sets return list(vocabSet) def setofWords2Ved(vocabList,inputSet) ''' 遍历查看该单词是否出现,出现该单词则将该单词置1 :param vocabList:全部单词集合列表 :return:匹配列表[0,1,0,1...],其中1与0表示词汇表中的单词是否出如今输入的数据集中 ''' #建立一个和词汇表等长的向量,并将其元素都设置为0 returnVec=[0]*len(vocabList)#[0,0,0...] #遍历文档中全部单词,若是出现了词汇表中的单词,则输出的文档向量中的对应值设为1 for word n inputSet: if word in vocabList: returnVec[vocabList.index(word)]=1 else: print ("the word :%s is not in my Vocabulary!" %word) return returnVec #朴素贝叶斯分类函数 def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1): p1=sum(vec2Classify*p1Vec)+np.log(pClass1) p2=sum(vec2Classify*p0Vec)+np.log(1.0-pClass1) if p1>p0: return 1 else : return 0 def spamTest(): ''' Desc:对贝叶斯垃圾邮件分类器进行自动化处理 Args:none Returns: ''' docList=[] classList=[] fullText=[] for i in range(1,26):#前26个文件 #切分,解析数据,并归类为1类别 wordList=textParse(open(r'文件路径/%d.txt'% i,encoding='ISO-8859-1')) docList.append(wordList) fullText.extend(wordList) classList.append(1) #切分,解析数据,并归类为0类别 wordList=textParse(open(r'文件路径/%d.txt'% i,encoding='ISO-8859-1')) docList.append(wordList) fullText.extend(wordList) classList.append(0) #建立词汇表 vocabList=createVocabList(docList) trainingSet=list(range(50)) testSet=[] #随机取10个邮件用来测试 for i in range(10): #random.uniform(x,y)随机生成一个范围为x-y的实数 trandIndex=int(random.uniform(0,len(trainingSet))) testSet.append(trainingSet[randIndex]) del(traningSet[randIndex]) trainMat=[] trainClasses=[] for docIndex in trainingSet: trainMat.append(setofWords2Ved(vocabList,docList(docIndex))) trainClasses.append(classList[docIndex]) p0v,p1v,pSpam=trainNB0(np.array(trainMat),np.array(trainClasses)) errorCount=0 for docIndex in testSet: wordVector=setofWords2Ved(vocabList,docList(docIndex)) if classifyNB(np.array(wordVector),p0v,p1v,pSpam)!=classList[docIndex]: errorCount+=1 print('the errorCount is :',errorCount) print('the testSet length is :',len(testSet)) print('the error rate is :',float(errorCount)/len(testSet)) import random import numpy as np import math spamTest()