朴素贝叶斯分类器python_机器学习之朴素贝叶斯及python代码实战

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对于给定的输入X,利用贝叶斯定理后验概率最大的输出Y

朴素贝叶斯方法 = 贝叶斯公式 + 条件独立假设(等于是说用于分类的特征在类确定的条件下都是条件独立的)。

贝叶斯公式:

e9fcd58eccc72fb594b36a48d3199975.png

其中P(Y)叫做先验概率,P(Y|X)叫做后验概率,P(Y,X)叫做联合概率;

1)P(“属于某类”|“具有某特征”)=在已知某样本“具有某特征”的条件下,该样本“属于某类”的概率。所以叫做『后验概率』;

2)P(“具有某特征”|“属于某类”)=在已知某样本“属于某类”的条件下,该样本“具有某特征”的概率;

3)P(“属于某类”)=在未知某样本具有该“具有某特征”的条件下,该样本“属于某类”的概率。所以叫做『先验概率』;

4)P(“具有某特征”)=在未知某样本“属于某类”的条件下,该样本“具有某特征”的概率。

由于计算时具有某特征而属于某类无法直接通过统计得到,比如有十个属性而求相应类概率是比较复杂的,但是反过来求对应类会有那些属性概率则可以通过统计得到,因此需要用到上面所说的概率公式将其转换。当然朴素贝叶斯算法有个更加强的假设,就是属性间相互独立,也就是概率可以进行相乘,这也是“朴素”贝叶斯的来源:

752080731ce6fb101bd0152cf8c51dbd.png

当特征属性为连续值时,通常假定其值服从高斯分布(也称正态分布)。

后验概率最大化的含义:等同于期望风险最小化;

后验概率最大化:在给定输入,通过学习到的模型计算后验概率,将后验概率最大的类作为特征的输出类;

dfc6d74aca50e52f0151b66e211c65e5.png

假设是解决一个二类问题,选择的是0-1损失函数:

fa0e4569193c9ce8932262b2ff813725.png

此时优化的目标是期望最小化

26efffc83cacaeeb6e9b5d6e14d92e8b.png

期望是对联合分布取得,由此取条件期望

8f590cd4b460275110e16ce98b94b7f4.png

为了使期望最小,只需要对逐个X=x最小,由此得到

91af2149d910a89ce0c70520c658ea8b.png

这样根据期望最小就得到了后验概率z最大化准则:

83510329d43addf8d99e77cd31e3a1c1.png

即朴素贝叶斯采用的原理。

用python基于朴素贝叶斯实现垃圾邮件过滤,该段代码主要参考机器学习实战;

#---------------------------从文本中构建词条向量-------------------------#1 要从文本中获取特征,需要先拆分文本,这里特征是指来自文本的词条,每个词#条是字符的任意组合。词条可以理解为单词,当然也可以是非单词词条,比如URL#IP地址或者其他任意字符串 #  将文本拆分成词条向量后,将每一个文本片段表示为一个词条向量,值为1表示出现#在文档中,值为0表示词条未出现#导入numpyfrom numpy import *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'],                 ['my','licks','ate','my','steak','how',\                  'to','stop','him'],                 ['quit','buying','worthless','dog','food','stupid']]    #由人工标注的每篇文档的类标签    classVec=[0,1,0,1,0,1]    return postingList,classVec#统计所有文档中出现的词条列表    def createVocabList(dataSet):    #新建一个存放词条的集合    vocabSet=set([])    #遍历文档集合中的每一篇文档    for document in dataSet:        #将文档列表转为集合的形式,保证每个词条的唯一性        #然后与vocabSet取并集,向vocabSet中添加没有出现        #的新的词条                vocabSet=vocabSet|set(document)    #再将集合转化为列表,便于接下来的处理    return list(vocabSet)#根据词条列表中的词条是否在文档中出现(出现1,未出现0),将文档转化为词条向量    def setOfWords2Vec(vocabSet,inputSet):    #新建一个长度为vocabSet的列表,并且各维度元素初始化为0    returnVec=[0]*len(vocabSet)    #遍历文档中的每一个词条    for word in inputSet:        #如果词条在词条列表中出现        if word in vocabSet:            #通过列表获取当前word的索引(下标)            #将词条向量中的对应下标的项由0改为1            returnVec[vocabSet.index(word)]=1        else: print('the word: %s is not in my vocabulary! '%'word')    #返回inputet转化后的词条向量    return returnVec#训练算法,从词向量计算概率p(w0|ci)...及p(ci)#@trainMatrix:由每篇文档的词条向量组成的文档矩阵#@trainCategory:每篇文档的类标签组成的向量def trainNB0(trainMatrix,trainCategory):    #获取文档矩阵中文档的数目    numTrainDocs=len(trainMatrix)    #获取词条向量的长度    numWords=len(trainMatrix[0])    #所有文档中属于类1所占的比例p(c=1)    pAbusive=sum(trainCategory)/float(numTrainDocs)    #创建一个长度为词条向量等长的列表    p0Num=zeros(numWords);p1Num=zeros(numWords)    p0Denom=0.0;p1Denom=0.0    #遍历每一篇文档的词条向量    for i in range(numTrainDocs):        #如果该词条向量对应的标签为1        if trainCategory[i]==1:            #统计所有类别为1的词条向量中各个词条出现的次数            p1Num+=trainMatrix[i]            #统计类别为1的词条向量中出现的所有词条的总数            #即统计类1所有文档中出现单词的数目            p1Denom+=sum(trainMatrix[i])        else:            #统计所有类别为0的词条向量中各个词条出现的次数            p0Num+=trainMatrix[i]            #统计类别为0的词条向量中出现的所有词条的总数            #即统计类0所有文档中出现单词的数目            p0Denom+=sum(trainMatrix[i])    #利用NumPy数组计算p(wi|c1)    p1Vect=p1Num/p1Denom  #为避免下溢出问题,后面会改为log()    #利用NumPy数组计算p(wi|c0)    p0Vect=p0Num/p0Denom  #为避免下溢出问题,后面会改为log()    return p0Vect,p1Vect,pAbusive#p0Num=ones(numWords);p1Num=ones(numWords)#p0Denom=2.0;p1Denom=2.0#p0Vect=log(p0Num/p0Denom);p1Vect=log(p1Num/p1Denom)#朴素贝叶斯分类函数#@vec2Classify:待测试分类的词条向量#@p0Vec:类别0所有文档中各个词条出现的频数p(wi|c0)#@p0Vec:类别1所有文档中各个词条出现的频数p(wi|c1)#@pClass1:类别为1的文档占文档总数比例def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):    #根据朴素贝叶斯分类函数分别计算待分类文档属于类1和类0的概率    p1=sum(vec2Classify*p1Vec)+log(pClass1)    p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1)    if p1>p0:        return 1    else:        return 0#分类测试整体函数        def testingNB():    #由数据集获取文档矩阵和类标签向量    listOPosts,listClasses=loadDataSet()    #统计所有文档中出现的词条,存入词条列表    myVocabList=createVocabList(listOPosts)    #创建新的列表    trainMat=[]    for postinDoc in listOPosts:        #将每篇文档利用words2Vec函数转为词条向量,存入文档矩阵中        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))\    #将文档矩阵和类标签向量转为NumPy的数组形式,方便接下来的概率计算    #调用训练函数,得到相应概率值    p0V,p1V,pAb=trainNB0(array(trainMat),array(listClasses))    #测试文档    testEntry=['love','my','dalmation']    #将测试文档转为词条向量,并转为NumPy数组的形式    thisDoc=array(setOfWords2Vec(myVocabList,testEntry))    #利用贝叶斯分类函数对测试文档进行分类并打印    print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))    #第二个测试文档    testEntry1=['stupid','garbage']    #同样转为词条向量,并转为NumPy数组的形式    thisDoc1=array(setOfWords2Vec(myVocabList,testEntry1))    print(testEntry1,'classified as:',classifyNB(thisDoc1,p0V,p1V,pAb))def bagOfWords2VecMN(vocabList,inputSet):    #词袋向量    returnVec=[0]*len(vocabList)    for word in inputSet:        if word in vocabList:            #某词每出现一次,次数加1            returnVec[vocabList.index(word)]+=1    return returnVec#贝叶斯算法实例:过滤垃圾邮件#处理数据长字符串#1 对长字符串进行分割,分隔符为除单词和数字之外的任意符号串#2 将分割后的字符串中所有的大些字母变成小写lower(),并且只#保留单词长度大于3的单词def testParse(bigString):    import re    listOfTokens=re.split(r'\W*',bigString)    return [tok.lower() for tok in listOfTokens if len(tok)>2]def spamTest():    #新建三个列表    docList=[];classList=[];fullTest=[]    #i 由1到26    for i in range(1,26):        #打开并读取指定目录下的本文中的长字符串,并进行处理返回        wordList=testParse(open('email/spam/%d.txt' %i).read())        #将得到的字符串列表添加到docList        docList.append(wordList)        #将字符串列表中的元素添加到fullTest        fullTest.extend(wordList)        #类列表添加标签1        classList.append(1)        #打开并取得另外一个类别为0的文件,然后进行处理        wordList=testParse(open('email/ham/&d.txt' %i).read())        docList.append(wordList)        fullTest.extend(wordList)        classList.append(0)    #将所有邮件中出现的字符串构建成字符串列表    vocabList=createVocabList(docList)    #构建一个大小为50的整数列表和一个空列表    trainingSet=range(50);testSet=[]    #随机选取1~50中的10个数,作为索引,构建测试集    for i in range(10):        #随机选取1~50中的一个整型数        randIndex=int(random.uniform(0,len(trainingSet)))        #将选出的数的列表索引值添加到testSet列表中        testSet.append(trainingSet[randIndex])        #从整数列表中删除选出的数,防止下次再次选出        #同时将剩下的作为训练集        del(trainingSet[randIndex])    #新建两个列表    trainMat=[];trainClasses=[]    #遍历训练集中的吗每个字符串列表    for docIndex in trainingSet:        #将字符串列表转为词条向量,然后添加到训练矩阵中        trainMat.append(setOfWords2Vec(vocabList,fullTest[docIndex]))        #将该邮件的类标签存入训练类标签列表中        trainClasses.append(classList[docIndex])    #计算贝叶斯函数需要的概率值并返回    p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClasses))    errorCount=0    #遍历测试集中的字符串列表    for docIndex in testSet:        #同样将测试集中的字符串列表转为词条向量        wordVector=setOfWords2Vec(vocabList,docList[docIndex])        #对测试集中字符串向量进行预测分类,分类结果不等于实际结果        if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:errorCount+=1        print('the error rate is:',float(errorCount)/len(testSet))

朴素贝叶斯算法是没有前后文信息的

在朴素贝叶斯眼里,“我司可办理正规发票”与“正规发票可办理我司”完全相同。朴素贝叶斯算法在进行文本分类时是没有前后文的。这就相当于把所有的词汇扔进到一个袋子里随便搅和,贝叶斯都认为它们一样。因此这种情况也称作词袋子模型(bag of words)

多项式模型

如果我们考虑重复词语的情况,也就是说,重复的词语我们视为其出现多次,直接按条件独立假设的方式推导,这样的模型叫作多项式模型。

伯努利模型

另一种更加简化的方法是将重复的词语都视为其只出现1次,这样的模型叫作伯努利模型(又称为二项独立模型)。这种方式更加简化与方便。当然它丢失了词频的信息,因此效果可能会差一些。

混合模型

第三种方式是在计算句子概率时,不考虑重复词语出现的次数,但是在统计计算词语的概率P("词语"|S)时,却考虑重复词语的出现次数,这样的模型可以叫作混合模型。

平滑技术

平滑技术都是给未出现在训练集中的词语一个估计的概率,而相应地调低其他已经出现的词语的概率。 使用高斯环境的贝叶斯分类器对几种数据得预测情况: 1)能够对一般数据起到很好分类作用;
"""=====================高斯环境的贝叶斯分类器=====================朴素贝叶斯分类器是一种基于贝叶斯理论的简单的概率分类器,而朴素的含义是指输入变量的特征属性之间具有很强的独立性。尽管这种朴素的设计和假设过于简单,但朴素贝叶斯分类器在许多复杂的实际情况下具有很好的表现,并且在综合性能上,该分类器要优于提升树(boosted trees)和随机森林(random forests)。在许多实际应用中,对于朴素贝叶斯模型的参数估计往往使用的是极大似然法,因此我们可以这么认为,在不接受贝叶斯概率或不使用任何贝叶斯方法的前提下,我们仍然可以应用朴素贝叶斯模型对事物进行分类。"""from sklearn.naive_bayes import GaussianNBfrom sklearn.datasets import make_moons, make_circles, make_classification#引入训练数据X, y = make_moons(noise=0.6, random_state=1)#定义高斯分类器类gnb = GaussianNB()#训练过程gnb.fit(X, y)#绘图库引入import matplotlib.pyplot as pltimport matplotlib as mplimport numpy as np#调整图片风格mpl.style.use('fivethirtyeight')#定义xy网格,用于绘制等值线图x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),                     np.arange(y_min, y_max, 0.1))#预测可能性Z = gnb.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1]Z = Z.reshape(xx.shape)plt.contourf(xx, yy, Z, alpha=.8)#绘制散点图plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k')plt.title("GaussianNaiveBayes")plt.axis("equal")plt.show()

0e744442cb0d38debba6d05f192cbca3.png

2)特定情况下等同于线性分类器;
"""=====================高斯环境的贝叶斯分类器=====================在训练数据协方差相同的情况下,高斯分类器等效于线性分类器"""from sklearn.naive_bayes import GaussianNBimport numpy as np#引入训练数据X1 = np.random.normal(size = [600, 2])X2 = np.random.random([600, 2])#方差均衡,使得两个类方差均为1X1 = X1/np.std(X1)X2 = X2/np.std(X2)y = np.concatenate([np.zeros_like(X1[:,0]), np.ones_like(X2[:,0])], axis=0)X = np.concatenate([X1, X2],axis=0)#定义高斯分类器类gnb = GaussianNB()#训练过程gnb.fit(X, y)#绘图库引入import matplotlib.pyplot as pltimport matplotlib as mplimport numpy as np#调整图片风格mpl.style.use('fivethirtyeight')#定义xy网格,用于绘制等值线图x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),                     np.arange(y_min, y_max, 0.1))#预测可能性Z = gnb.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1]Z = Z.reshape(xx.shape)plt.contourf(xx, yy, Z, alpha=.8)#绘制散点图plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k')plt.title("GaussianNaiveBayes")plt.axis("equal")plt.show()

35fe5a9e757b81a8fdf7e2d641a0e8b8.png

3)鸢尾花数据划分情况;
"""=====================贝叶斯分类器用于鸢尾花数据=====================由Fisher在1936年整理,包含4个特征(Sepal.Length(花萼长度)、Sepal.Width(花萼宽度)、Petal.Length(花瓣长度)、Petal.Width(花瓣宽度))特征值都为正浮点数,单位为厘米。目标值为鸢尾花的分类(Iris Setosa(山鸢尾)、Iris Versicolour(杂色鸢尾),Iris Virginica(维吉尼亚鸢尾))。"""from sklearn import datasetsfrom sklearn.naive_bayes import GaussianNBfrom sklearn.decomposition import PCAiris = datasets.load_iris()#选择两个属性,便于绘图X = iris.datay = iris.targetpca = PCA(n_components=2)X = pca.fit(X).transform(X)#定义高斯分类器类gnb = GaussianNB()#训练过程gnb.fit(X, y)#绘图库引入import matplotlib.pyplot as pltimport matplotlib as mplimport numpy as np#调整图片风格mpl.style.use('fivethirtyeight')#定义xy网格,用于绘制等值线图x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),                     np.arange(y_min, y_max, 0.1))#预测可能性pdt = gnb.predict_proba(np.c_[xx.ravel(), yy.ravel()])Z = pdt[:, 0]Z = Z.reshape(xx.shape)plt.contourf(xx, yy, Z, alpha=.6)Z = pdt[:, 1]Z = Z.reshape(xx.shape)plt.contourf(xx, yy, Z, alpha=.6)#绘制散点图plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k')plt.title("GaussianNaiveBayes")plt.axis("equal")plt.show()

e9466ece45c86a19e2e002183a536427.png

本文参考《统计学习方法》《机器学习实战》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值