算法学习笔记更新,本章内容是朴素贝叶斯,是一个用到概率论的分类方法。

算法简介

  朴素贝叶斯是贝叶斯决策的一部分,简单说,就是利用条件概率来完成分类。说起条件概率,猛地一下戳到了笔者的伤口。想当年,在学完概率论两年的日子里,它再也没有被我宠幸过。常言道:“谁会考完试了还去看书呢?” 没毛病,我就是那些考完试不看书的人之一。自信满满地走进了推免面试场,被一波数学问题轰炸的败下阵来,其中就包括条件概率。总结:学好概率论、学好线代,it is very important. 至少在一些高校面试的时候会被问道。说多了都是泪,往者不谏,来者可追,come on ,学起来!

  什么是条件概率,不念天书,说普通话,就是说有两个事情,暂设为A和B,问事件A发生的情况下,事件B发生的概率是多少,记为P(B|A)。或者说事件B发生的情况下,求事件A发生的概率,记为P(A|B)。

  举个例子,有一对夫妻,生了两个孩子,已知其中一个是女孩,求另外一个是男孩的概率?
   当然,不是1/2,有个条件,”已知其中一个是女孩“,这是一个条件概率题,我们来列举一下,两个孩子的所有可能为:男+男、男+女、女+女、女+男。
已知其中一个为女孩,则对应三种情况:男+女、女+女、女+男,另一个为男孩的概率,显然为2/3
这道题除了通过列举法列举出结果之外,用条件概率公式可以计算:

  由条件概率公式推导出乘法公式为:

条件概率是朴素贝叶斯进行分类的主要内容,下面我们通过文档分类的例子来具体理解算法分类过程以及条件概率在朴素贝叶斯分类种的应用。

使用朴素贝叶斯进行文档分类

问题描述:

  有一些数量有限的文档,一篇文档由有限数量的单词组成,这些文档的类别已知,对应侮辱类/非侮辱类。如果又填入几份文档,问新填入的文档类别是什么?

问题求解:

  对文档进行分类时,侮辱类还是非侮辱类,可以通过观察文档中的词,并把每个词出现或者不出现作为一个特征。当我们拥有一个词汇表(包含很多的词汇,内容不重复)时,每一份文档中的特征数目都和词汇表中的词数目一样多。举个例子,见下图

  朴素贝叶斯分类器,有两个假设:一、假设所有特征之间是独立的。这也是之所以称之为“朴素”的原因,简单,直接。也就是说每份文档中一个单词出现与否,不受其他单词影响,统计意义上是独立的。例如:I have a beautiful sister,或者,The ice cream is delicious, 句子中每一个单词出现的可能性跟其他单词均无关系。常识告诉我们,这个假设太武断了,ice cream与delicious或者其他味道的形容词,二者之间肯定不是彼此独立的,因为这些味道的形容词常常伴随着ice cream出现。二、假设每一个特征是同等重要的,也就是说每个特征赋予的权重是一样的,根据经验来说,这个假设也存在问题,拿文档分类的例子来说,一篇文档的类别可能不需要看完词汇表中所有单词,只根据少数的特征就能做出判断了。例如I want to tell you,you are so stupid, do you know?,这句话中,so stupid两个单词,这两个特征对于文档分类起的作用更大。因此,我们说,假设二也是存在问题的。虽然假设存在瑕疵,但是,这两个假设让问题变的简单,我们不必考虑特征之间的依赖性,也不必考虑特征权重。而且,朴素贝叶斯实际进行文档分类时,效果很好。

将上述条件概率公式进行转换,用于求文档分类问题。(用w替代B,ci替代A)

可以理解为现有一篇文档w,(w是文档词汇的组合向量,假设文档包含4个单词),求文档属于ci 的概率。若P(c1|w)> P(c2|w),则文档为第一类,否则为第二类。这就是朴素贝叶斯进行分类的依据。如果要对文档w进行分类,那么要计算出p(w|ci),朴素贝叶斯假设所有特征之间是独立的,所以

依据条件概率可知,还需要计算出p(c i),即训练集中两种类别的比例,这个很方便计算。清楚如何求解后,下面进行程序实现。

程序实现

  写程序之前,需要明确,程序要完成的功能。首先,我们有一些文档集,要通过这些文档集构建一张词汇表。通过这张词汇表,对每一篇文档进行文本到向量的转换,也就是说需要把一串串单词转换为向量。如果要对新的一篇文档Q进行分类,依照条件概率公式,需要计算出p(ci),即p( c1 )和p( c2 ),以及p(w | ci),计算这三个值的过程也就是训练分类器的过程。有了这些值,我们就可以计算P(ci | w),从而得出这篇文档输入每个类别的概率,通过比较概率,得出分类结果。

程序流程:加载数据集——构建词汇表——文本转向量——训练分类器——测试分类器

加载数据集

##############加载数据集###############
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']]postingLabel=[0,1,0,1,0,1]return postingList,postingLabelpostingList,postingLabel=loadDataSet()
print(postingList,'\n',postingLabel)

程序输出

[['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, 0, 1, 0, 1]

构建词汇表

#####构建词汇表######################
def createVocabList(postingList):vocabSet=set()for posting in postingList:vocabSet= vocabSet | set(posting)   ##集合并集,集合中元素唯一return list(vocabSet)

词条转向量

###将词条转换为文本向量##############
'''
一条一条的转换,调用一次转换一条
returnVec:返回文本转换后的向量,由0、1组成
'''
def word2vec(vocabList,posting):returnVec=[0]*len(vocabList)  #创建1*len(vocabList) 维度的数组,存储词条向量for word in posting: #print(word)if word in vocabList:index=vocabList.index(word)returnVec[index]=1     #词汇表中存在该词,则对应位置为1,否则为0   else:print(word)return returnVec#功能测试
postingList,postingLabels=loadDataSet()
vocablist=createVocabList(postingList)
print("词表长度为:",len(vocablist))
print("['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'] 这个字条转向量,结果为:")
print(word2vec(vocablist,postingList[0]))

功能测试:

词表长度为: 32
['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'] 这个字条转向量,结果为:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0]

训练分类器

def train(trainMat,postingLabels):'''计算trainMat中,每个词语属于侮辱类的概率p1A,以及非侮辱类的概率 p0A。计算方法:计算这个词与所有侮辱类文档词汇之和的比例。若一个词在三篇侮辱文档中同时出现,就是1+1+1为3,向量对应位置相加而得。若一个词在一篇侮辱文档中出现三次,向量还是1,因为在转为向量的时候,出现即为1,没有是0,并不统计次数。trainMat相当于训练集,用于计算p1A,p0A,'''numDoc=len(trainMat)numWord=len(trainMat[0])p1=zeros(numWord)     #初始p1,全0向量p0=zeros(numWord)      #初始p0,全0向量pAbusive=sum(postingLabels)/float(numDoc)  #计算侮辱类文档所占比例p1WordSum=0.0 p0WordSum=0.0for i in range(numDoc):if postingLabels[i]==1:p1+=trainMat[i]                       #向量相加p1WordSum+=sum(trainMat[i])           #统计所有侮辱性言论所包含的词的个数else:p0 +=trainMat[i]p0WordSum +=sum(trainMat[i])p1A=p1/p1WordSum                           #计算所有非侮辱类文档向量之和后,每个词对应的概率。比如,上述相加之后,向量为[3,1,0,9],p1Denom=13,列表里的值越高,证明这个词在多篇侮辱类文档中出现,相应地,这个词语属于侮辱类的概率也就越大,为9/13p0A=p0/p0WordSumreturn p1A,p0A,pAbusive#########功能测试
postingList,postLabels=loadDataSet()
vocabList=createVocabList(postingList)
trainMat=[]
for posting in postingList:trainMat.append(word2vec(vocabList,posting))
p1A,p0A,pAbusive=train(trainMat,postLabels)
print("p1A= ",p1A)
print("p0A= ",p0A)
print("pAbusive= ",pAbusive)

程序输出:

 需要说明的一点:程序中的p1A对应p(w1 |c1)、p(w2 |c1)、p(w3 |c1)……  p0A对应p(w1 |c2)、p(w2 |c2)、p(w3 |c2)……pAbusive为侮辱类文档的占比,p(c1)`
p1A=  [0.         0.         0.         0.         0.05263158 0.0.         0.         0.05263158 0.05263158 0.         0.0.10526316 0.05263158 0.10526316 0.         0.05263158 0.0.05263158 0.05263158 0.         0.05263158 0.         0.0.05263158 0.         0.         0.05263158 0.05263158 0.0.05263158 0.15789474]
p0A=  [0.04166667 0.04166667 0.125      0.04166667 0.04166667 0.041666670.04166667 0.04166667 0.         0.         0.04166667 0.041666670.04166667 0.         0.         0.04166667 0.         0.041666670.         0.08333333 0.04166667 0.         0.04166667 0.041666670.         0.04166667 0.04166667 0.04166667 0.         0.041666670.         0.        ]
pAbusive=  0.5

测试分类器:

#######构建分类器#######
def classify(p1A,p0A,inputVec,pClass1):#参照朴素贝叶斯公式p1=sum(p1A*inputVec)+log(pClass1)       #分母都是一样的,所以此处计算分子即可p0=sum(p0A*inputVec)+log(1.0-pClass1)if p1>p0:return 1else:return 0###########测试函数#############
def test():postingList,postLabels=loadDataSet()  #加载数据集vocabList=createVocabList(postingList) #创建词汇表trainMat=[]     #创建存储训练集词条的向量for postVec in postingList:trainMat.append(word2vec(vocabList,postVec))   #填充训练集p1A,p0A,pAbusive=train(trainMat,postLabels)    #训练分类器,得到概率值testEntry=['stupid','garbage','love']    #测试实例一testVec=word2vec(vocabList,testEntry)    #转换为词条向量result=classify(p1A,p0A,testVec,pAbusive)   #扔入分类器中print(testEntry,'classified as ',result)    #输出分类结果testEntry2=['I','love','the','dog']testVec=array(word2vec(vocabList,testEntry2))  result=classify(p1A,p0A,testVec,pAbusive)print(testEntry2,'classified as ',result)

根据现实情况修改分类器:
(1)p1、p0初始化全为0,如果词汇表中的一些词语在待分类文档中不存在或者训练集中某一条文档不能全部包含词汇表中的词语(其实这两种情况本质上一样的),那么经过向量累加后,p1中会有0,如下图的情况:

在计算p(w1|ci)*p(w2|ci)*p(w3|ci)……*p(w9|ci)时,一项为0,会导致整个文档分类的概率结果为0。因此,为了避免这种情况,p1、p0初始化全为1,这种解决0概率的方法,叫做拉普拉斯平滑
(2)通过上面程序输出,我们可以看到,p1、p0都是很小的浮点数,概率相乘,p(w1|ci)*p(w2|ci)*p(w3|ci)p(w4|ci)……,当项数很多时,容易导致下溢出。中学时代我们学过ln(xy)=lnx+lny,可以通过取自然对数来避免下溢出。在分类器中,进行如下更改

#更改一:将train函数里面下面两行:p1=zeros(numWord)     #初始p1,全0向量p0=zeros(numWord)      #初始p0,全0向量
更改为:
p1=ones(numWord)     #初始p1,全1向量
p0=ones(numWord)      #初始p0,全1向量#更改二::将train函数里下面两行p1A=p1/p1WordSum p0A=p0/p0WordSum
#更改为:p1A=numpy.log(p1/p1WordSum)   p0A=numpy.log(p0/p0WordSum)

修改之后,执行测试函数test(),测试结果如下:其中1 代表侮辱类,0代表非侮辱类

['stupid', 'garbage', 'love'] classified as  1
['I', 'love', 'the', 'dog'] classified as  0

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

问题描述
  在文档分类的例子中,输入数据是切分好的字符串列表,如[‘I’, ‘love’, ‘the’, ‘dog’],实际情况中,我们往往要经过一些处理后才能得到这样的字符串列表。在过滤垃圾邮件问题时,邮件存储在txt文件中,我们需要从中读取字符串,进行切分处理,从而实现词条到向量的转换。

程序实现:

#############词袋模型VS词集模型#############
def bagOfWords2VecMN(vocabList,inputSet):  '''词袋模型VS词集模型:词袋模型:文档中的词语在词表中出现一次就+1词集模型:出现为1,不出现为0,不累加'''  returnVec=[0]*len(vocabList)for word in inputSet:if word in vocabList:returnVec[vocabList.index(word)]+=1return returnVec###########################文本解析函数###########
def textParse(bigString):import relistOfToken=re.split('\\W*',bigString)     #除单词字符、数字以外的符号均当作切分符return [tok.lower() for tok in listOfToken if len(tok)>0]########################邮件过滤测试####################
def emailTest():docList=[];labelList=[];vocabList=[]##读取两个文件夹的文件for i in range(1,26):wordList=textParse(open('email/spam/%d.txt' %i).read())docList.append(wordList) labelList.append(1)wordList=textParse(open('email/ham/%d.txt' %i).read())docList.append(wordList)labelList.append(0)##创建词表vocabList=createVocabList(docList)'''留存交叉验证:随机选择数据的一部分作为训练集,剩余的部分作为测试集。'''#创建训练集和测试集合,集合里面存储的是文件索引trainSet=list(range(30))  #训练集邮件数量设置为30,可以通过调整,观察分类结果testSet=[]for i in range(10):randIndex=int(random.uniform(0,len(trainSet)))testSet.append(randIndex)del(trainSet[randIndex])trainMat=[]tr_label=[]for index in trainSet:trainMat.append(word2vec(vocabList,docList[index]))tr_label.append(labelList[index])p1A,p0A,pAbusive=train(array(trainMat),array(tr_label))errorCount=0.0for test_index in testSet:test_Vec=word2vec(vocabList,docList[test_index])result=classify(p1A,p0A,test_Vec,pAbusive)if result!=labelList[test_index]:errorCount+=1print('错误率为%f'%(errorCount/len(testSet)))emailTest()

为了更精确的评估分类器分类准确率,可以进行多次迭代,求平均错误率。将测试集邮件数量设置为30时,运行多次,测试结果为

错误率为0.500000
错误率为0.300000
错误率为0.300000
错误率为0.100000

总结:

算法优点:
   1、概率理论发展历史悠久,使得模型有稳定的分类效率
   2、算法简单,好理解,并且对缺失值不敏感
算法缺点:
  考虑现实情况,两个假设存在问题。当数据集特征关联性较大时,分类效果未必会好。

就到这了~~~ 码字有些累了,想不起来的知识点以后再补充吧~

独学无朋,则孤陋而难成,如果有不理解的地方,欢迎与我交流,我们可以共同学习!学海无涯,个人整理,内容难免会有纰漏,欢迎道友指正,感激不尽!

本文参考学习资料:《机器学习实战》(peter Harrington 著)

机器学习算法(三):基于概率论的分类方法:朴素贝叶斯理论与python实现+经典应用(文档分类、垃圾邮件过滤)相关推荐

  1. 《机器学习实战》学习笔记(四):基于概率论的分类方法 - 朴素贝叶斯

    欢迎关注WX公众号:[程序员管小亮] [机器学习]<机器学习实战>读书笔记及代码 总目录 https://blog.csdn.net/TeFuirnever/article/details ...

  2. 基于概率论的分类方法—朴素贝叶斯

    基于概率论的分类方法-朴素贝叶斯 转载于:https://www.cnblogs.com/liuys635/p/11181304.html

  3. 机器学习实战教程(三):基于概率论的分类方法——朴素贝叶斯

    文章目录 一.朴素贝叶斯理论 1.贝叶斯决策理论 2.条件概率 3.全概率公式 4.贝叶斯推断 5.朴素贝叶斯推断 二.示例:言论过滤器 三.朴素贝叶斯改进之拉普拉斯平滑 四.示例:朴素贝叶斯之过滤垃 ...

  4. 基于概率论的分类方法: 朴素贝叶斯

    朴素贝叶斯 概述 贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类.本章首先介绍贝叶斯分类算法的基础--贝叶斯定理.最后,我们通过实例来讨论贝叶斯分类的中最简单的一种: ...

  5. 机器学习监督学习之分类算法---朴素贝叶斯理论知识

    感谢Jack-Cui大佬的知识分享 机器学习专栏点击这里 目录 感谢Jack-Cui大佬的知识分享 0. 概述 1. 朴素贝叶斯理论 1.1 贝叶斯理论 1.1.1 相关计算公式:条件概率公式,贝叶斯 ...

  6. Python《机器学习实战》读书笔记(四)——朴素贝叶斯

    第四章 基于概率论的分类方法朴素贝叶斯 4-1 基于贝叶斯决策理论的分类方法 4-2 条件概率 4-3 使用条件概率来分类 4-4 使用朴素贝叶斯进行文档分类 4-5 使用Python进行文本分类 4 ...

  7. 无监督学习------分类学习-----朴素贝叶斯(navie bayes)

    朴素贝叶斯是一个实用性很强的分类模型,不过线性分类器和支持向量机分类器(基于线性假设的模型)不同,朴素贝叶斯的构造基础是贝叶斯理论 这个模型的基本数学假设是:各个维度上的特征被分类的条件概率之间是相互 ...

  8. 机器学习算法——朴素贝叶斯(贝努利模型和多项式模型实现分类)

    朴素贝叶斯算法 0.朴素贝叶斯是贝叶斯决策理论的一部分.之所以称之为"朴素",是因为整个形式化过程只做最原始.最简单的假设. 1.文本分类实例 2.朴素贝叶斯过滤垃圾邮件 3.使用 ...

  9. 基于朴素贝叶斯分类器的西瓜数据集 2.0 预测分类_朴素贝叶斯(转载自Morgan)...

    什么是朴素贝叶斯 要搞懂朴素贝叶斯分类,首先需要了解什么是贝叶斯定理和特征条件独立假设,朴素贝叶斯算法就是基于这两个来实现的分类方法. 贝叶斯定理 贝叶斯定理通俗点讲就是求在事件 B 已经发生的前提下 ...

最新文章

  1. Windows批处理脚本%1和%1%有区别吗?
  2. el-select 结合 el-checkBox 实现下拉全选+多选功能;el-select下拉框全选功能;
  3. 云栖社区云栖号(团队博客)攻略【2018版】
  4. 【Kafka】Kafka 镜像 Kafka mirroring (MirrorMaker)
  5. 数据结构与算法 实验二:利用单链表(实现ADT)判断回文
  6. C++的基础知识【面试遇到】
  7. Struts,Spring,Hibernate三大框架的面试
  8. wincc安装信息服务器,WinCC 7.4软件不会安装?怎么授权?一文教会你
  9. 简析发送手机验证码原理
  10. 前端工程师的摸鱼日常(2)
  11. 『MongoDB』MongoDB的数据存储格式Bson比Json有哪些优势?
  12. 什么是5G承载网?【转载自微信公众号网络技术联盟站】
  13. AndroidStudio利用android-support-multidex解决65536问题64k问题
  14. [读论文] Electric Drive Technology Trends, Challenges, and Opportunities for Future Electric Vehicles
  15. matlab设计一个AM调幅广播传输系统,基于Simulink的调幅广播系统的仿真与分析
  16. HelloWord代码
  17. morlet包络检波matlab,包络检波技术,envelope detection technique,音标,读音,翻译,英文例句,英语词典...
  18. OPNET网络仿真分析-前言
  19. 法国电信公司裁员,导致19名员工自杀身亡,12人自杀未遂!
  20. 对某音乐网站歌曲链接抓取的分析

热门文章

  1. 数据美化 | 更清晰的Python词云wordcloud
  2. azkaban安装使用
  3. RecyclerView 悬浮/粘性头部——StickyHeaderDecoration
  4. 数字平原次世代角色搭建《堕天使》
  5. 喜马拉雅xm格式转化mp3_如何做好音频,在喜马拉雅赚钱月入上万!
  6. 今天读了奋斗B的讨论
  7. 中国城市空气质量查询及可视化bs4+wxpython
  8. 2021杭电多校补题(2)
  9. 计算机毕业设计SSM高考志愿智能填报系统【附源码数据库】
  10. 渗透测试-Z宝典(Penetration-Zbook)