初识分类算法(3)-----朴素贝叶斯算法

1. 例子引入:如上篇的play or not 例子。

未知分类的样本:D:<A=sunny, B=cool, C=high ,D=strong>,  是 or 否?

我们要判断该样本的分类,即比较该样本属于是的概率大还是否的概率大 P(是/否|A=sunny, B=cool, C=high ,D=strong)

P(是|A=sunny, B=cool, C=high ,D=strong)=P(是,(A=sunny, B=cool, C=high ,D=strong))/P(A=sunny, B=cool, C=high,D=strong)

分母不变,转化为比较分子,P(是,(A=sunny, B=cool, C=high ,D=strong))=P(A=sunny, B=cool, C=high ,D=strong|是)*P(是)

=P(A=sunny|是)*P(B=cool|是)*P(C=high|是)*P(D=strong|是)*P(是)

P(是)=9/14  P(否)=5/14    P(A=sunny|是)=2/5  P(A=sunny|否)=3/5

类似算出P(B=cool|是),P(B=cool|否),P(C=high|是),P(C=high|否),P(D=strong|是),P(D=strong|否)。

那么该未知分类的样本属于是/否的概率分别是:

是: P(是)*P(A=sunny|是)*P(B=cool|是)*P(C=high|是)*P(D=strong|是)=?1

否:P(否)*P(A=sunny|否)*P(B=cool|否)*P(C=high|否)*P(D=strong|否)=?2

?1>?2,则该未知分类的样本输出是。

2.  朴素贝叶斯分类的原理与流程

朴素贝叶斯分类是一种十分简单的分类算法,叫它朴素贝叶斯分类是因为这种方法的思想真的很朴素,朴素贝叶斯 的思想基础是这样的:对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,哪个最大,就认为此待分类项属于哪个类别。通俗来说,就好比这么个 道理,你在街上看到一个黑人,我问你你猜这哥们哪里来的,你十有八九猜非洲。为什么呢?因为黑人中非洲人的比率最高,当然人家也可能是美洲人或亚洲人,但 在没有其它可用信息下,我们会选择条件概率最大的类别,这就是朴素贝叶斯的思想基础。

朴素贝叶斯分类的正式定义如下:

1、设为一个待分类项,而每个a为x的一个特征属性。

2、有类别集合

3、计算

4、如果,则

那么现在的关键就是如何计算第3步中的各个条件概率。我们可以这么做:

1、找到一个已知分类的待分类项集合,这个集合叫做训练样本集。

2、统计得到在各类别下各个特征属性的条件概率估计。即

3、如果各个特征属性是条件独立的,则根据贝叶斯定理有如下推导:

因为分母对于所有类别为常数,因为我们只要将分子最大化皆可。又因为各特征属性是条件独立的,所以有:

根据上述分析,朴素贝叶斯分类的流程可以由下图表示(暂时不考虑验证):

      可以看到,整个朴素贝叶斯分类分为三个阶段:

第一阶段——准备工作阶段,这个阶段的任务是为朴素贝叶斯分类做必要的准备,主要工作是根据具体情况确定特征属性,并对每个特征属性进行适当划分,然后由 人工对一部分待分类项进行分类,形成训练样本集合。这一阶段的输入是所有待分类数据,输出是特征属性和训练样本。这一阶段是整个朴素贝叶斯分类中唯一需要 人工完成的阶段,其质量对整个过程将有重要影响,分类器的质量很大程度上由特征属性、特征属性划分及训练样本质量决定。

第二阶段——分类器训练阶段,这个阶段的任务就是生成分类器,主要工作是计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率估 计,并将结果记录。其输入是特征属性和训练样本,输出是分类器。这一阶段是机械性阶段,根据前面讨论的公式可以由程序自动计算完成。

第三阶段——应用阶段。这个阶段的任务是使用分类器对待分类项进行分类,其输入是分类器和待分类项,输出是待分类项与类别的映射关系。这一阶段也是机械性阶段,由程序完成。

3.估计类别下特征属性划分的条件概率及Laplace校准

      这一节讨论P(a|y)的估计。

由上文看出,计算各个划分的条件概率P(a|y)是朴素贝叶斯分类的关键性步骤,当特征属性为离散值时,只要很方便的统计训练样本中各个划分在每个类别中出现的频率即可用来估计P(a|y),下面重点讨论特征属性是连续值的情况。

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

因此只要计算出训练样本中各个类别中此特征项划分的各均值和标准差,代入上述公式即可得到需要的估计值。均值与标准差的计算在此不再赘述。

另一个需要讨论的问题就是当P(a|y)=0怎么办,当某个类别下某个特征项划分没有出现时,就是产生这种现象,这会令分类器质量大大降低。为了解决这个 问题,我们引入Laplace校准,它的思想非常简单,就是对没类别下所有划分的计数加1,这样如果训练样本集数量充分大时,并不会对结果产生影响,并且 解决了上述频率为0的尴尬局面。

4. 朴素贝叶斯的实例应用, 并用python实现

4.1 从文本文档中构建自己的词列表

 1 #-*-coding:utf-8-*-‘
 2 mysent=‘A man is not old until regrets take the place of dreams. (J. Barrymore)‘
 3 print mysent.split()
 4 import re
 5 regEX=re.compile(‘\\W*‘)  # 使用正则表示式来切分句子,其中分隔符是除单词,数字外的任意字符串。
 6 listoftokens=regEX.split(mysent)
 7 print listoftokens
 8 print [tok for tok in listoftokens if len(tok)>0]   #去掉空字符串
 9 print [tok.lower() for tok in listoftokens if len(tok)>0]  #将字符串全部转为小写
10
11 ####函数
12 def textParse(bigString):    #input is big string, #output is word list
13     import re
14     listOfTokens = re.split(r‘\W*‘, bigString)
15     return [tok.lower() for tok in listOfTokens if len(tok) > 2] 

cut list

先看一个简单的例子。

训练集是从聊天室里摘取的6句话,每句话都有一个标签0或者1,表示是否是辱骂信息(abusive or not abusive)。当然可以把每个消息看成是一个文档,只不过文档单词比这个多,但是一样的道理。

 1 def loadDataSet():
 2     postingList=[[‘my‘, ‘dog‘, ‘has‘, ‘flea‘, ‘problems‘, ‘help‘, ‘please‘],
 3                  [‘maybe‘, ‘not‘, ‘take‘, ‘him‘, ‘to‘, ‘dog‘, ‘park‘, ‘stupid‘],
 4                  [‘my‘, ‘dalmation‘, ‘is‘, ‘so‘, ‘cute‘, ‘I‘, ‘love‘, ‘him‘],
 5                  [‘stop‘, ‘posting‘, ‘stupid‘, ‘worthless‘, ‘garbage‘],
 6                  [‘mr‘, ‘licks‘, ‘ate‘, ‘my‘, ‘steak‘, ‘how‘, ‘to‘, ‘stop‘, ‘him‘],
 7                  [‘quit‘, ‘buying‘, ‘worthless‘, ‘dog‘, ‘food‘, ‘stupid‘]]
 8     classVec = [0,1,0,1,0,1]    #1 is abusive, 0 not
 9     return postingList,classVec
10 listoposts,listclasses=loadDataSet()

loadDataSet()

4.3 现在有6个文档的词列表,并且有它们对应的分类,将词表合并。该函数返回一个由唯一单词组成的词汇表

1 def createVocabList(dataSet):
2     vocabSet = set([])  #create empty set
3     for document in dataSet:
4         vocabSet = vocabSet | set(document) #union of the two sets
5     return list(vocabSet)
6 myvocablist=createVocabList(listoposts)

词库

print len(myvocablist)   #32

4.4  这个函数功能:输入词汇表和消息,通过逐个索引词汇表,然后看消息中的是否有对应的字在词汇表中,如果有就标记1,没有就标记0,这样就把每条消息都转成了和词汇表一样长度的有0和1组成的特征向量

 1 def setOfWords2Vec(vocabList, inputSet):
 2     returnVec = [0]*len(vocabList)
 3     for word in inputSet:
 4         if word in vocabList:
 5             returnVec[vocabList.index(word)] = 1
 6         else: print "the word: %s is not in my Vocabulary!" % word
 7     return returnVec
 8 #a1=setOfWords2Vec(myvocablist, listoposts[0])
 9 #print len(a1) #32
10 #a6=setOfWords2Vec(myvocablist, listoposts[5])
11 trainmat=[]
12 for i in listoposts:
13     trainmat.append(setOfWords2Vec(myvocablist, i))

trainmat

4.5 首先计算P(class=1),然后分别求出训练样本中,每一类:对每个元素除以该类别的总数,返回两个向量。P(a(i)|class=1),P(a(i)|class=0)

 1 def trainNB0(trainMatrix,trainCategory):
 2     numTrainDocs = len(trainMatrix)
 3     print numTrainDocs
 4     numWords = len(trainMatrix[0])
 5     print numWords
 6     pAbusive = sum(trainCategory)/float(numTrainDocs)
 7     print sum(trainCategory)
 8     p0Num = ones(numWords); p1Num = ones(numWords)      #change to ones()
 9     p0Denom = 2.0; p1Denom = 2.0                        #change to 2.0
10     for i in range(numTrainDocs):
11         if trainCategory[i] == 1:
12             p1Num += trainMatrix[i]
13             p1Denom += sum(trainMatrix[i])
14         else:
15             p0Num += trainMatrix[i]
16             p0Denom += sum(trainMatrix[i])
17     p1Vect = log(p1Num/p1Denom)     #change to log()
18     p0Vect = log(p0Num/p0Denom)          #change to log()
19     return p0Vect,p1Vect,pAbusive
20 p0v,p1v,pab=trainNB0(trainmat,listclasses)

trainNB0

上面的代码中输入的是特征向量组成的矩阵,和一个由标签组成的向量,其中pAbusive是类别概率P(ci),因为只有两类,计算一类后,另外一类可以 直接用1-p得出。接下来初始化计算p(wi|c1)和p(wi|c0)的分子和分母,这里惟一让人好奇的就是为什么分母p0Denom和p1Denom 都初始化为2?这是因为在实际应用中,我们计算出了(公式三)右半部分的概率后,也就是p(wi|ci)后,注意wi表示消息中的一个字,接下来就是判断 整条消息属于某个类别的概率,就要计算p(w0|1)p(w1|1)p(w2|1)的形式,这样如果某个wi为0,这样整个概率都为0,或者都很小连乘后会更小,甚至round off 0。这样就会影响判断,因此把他们转到对 数空间中来做运算,对数在机器学习里经常用到,在保持单调的情况下避免因数值运算带来的歧义问题,而且对数可以把乘法转到加法运算,加速了运算。因此上面 的代码中把所 有的出现次数初始化为1,然后把分母初始为2,接着都是累加,在对数空间中从0还是1开始累加,最后比较大小不会受影响的。

4.6 对未知的分类样本testEntry = [‘love‘, ‘my‘, ‘dalmation‘] 和 testEntry = [‘stupid‘, ‘garbage‘] 进行测试

并且classifyNB函数:计算了

 1 def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
 2     p1 = sum(vec2Classify * p1Vec) + log(pClass1)    #element-wise mult
 3     p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
 4     if p1 > p0:
 5         return 1
 6     else:
 7         return 0
 8
 9 listOPosts,listClasses = loadDataSet()
10 myVocabList = createVocabList(listOPosts)
11 #print len(myVocabList)
12 trainMat=[]
13 for postinDoc in listOPosts:
14     trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
15 p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
16 testEntry = [‘love‘, ‘my‘, ‘dalmation‘]
17 thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
18 print testEntry,‘classified as: ‘,classifyNB(thisDoc,p0V,p1V,pAb)
19 testEntry = [‘stupid‘, ‘garbage‘]
20 thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
21 print testEntry,‘classified as: ‘,classifyNB(thisDoc,p0V,p1V,pAb)

classifyNB

5.  朴素贝叶斯法属于生成方法,关键在于找到输入输出的联合分布,或者说确定联合分布的参数也就确定了联合分布。在特征条件独立的假设下,对每一个特征通过频率求解其条件概率分布,这些条件概率分布最终用于求解后验概率。根据后验概率来判断,选择P(Ci|X)最大的作为X的类别Ci,另外朴素贝叶斯只所以被称为朴素的原因是,它假设了特征之间都是独立的。可是,现实中往往特征之间不会是相互独立的,改进的做法:贝叶斯网络。

时间: 10-11

初识分类算法(3)-----朴素贝叶斯算法的相关文章

挖掘算法(1)朴素贝叶斯算法

原文:http://www.blogchong.com/post/NaiveBayes.html 1 文档说明 该文档为朴素贝叶斯算法的介绍和分析文档,并且结合应用实例进行了详细的讲解. 其实朴素贝叶斯的概念以及流程都被写烂了,之所以写这些是方便做个整理,记录备忘.而实例部分进行了详细的描述,网络上该实例比较简单,没有过程. 至于最后部分,则是对朴素贝叶斯的一个扩展了,当然只是简单的描述了一下过程,其中涉及到的中文分词以及TFIDF算法,有时间再具体补上. 2 算法介绍 2.1 贝叶斯定理 (1

统计学习方法 -&gt; 朴素贝叶斯算法

需要知道的是在什么时候可以用朴素贝叶斯算法:需要保证特征条件独立. 主要过程是学习输入和输出的联合概率分布. 预测的时候,就可以根据输入获得对打后验概率对应的输出y. 先验概率:已知输出,求输入.后验概率相反. 简单来说朴素贝叶斯算法,就是在对样本进行学习之后,到了需要做决策的时候,给定x,给出最大概率的y.这个本质上就是一个典型的后验概率模型.不过在该模型的算法推到上,还用到了先验概率的计算.但注意:最终朴素贝叶斯就是一种后验概率模型求P(y|x). 后验概率模型有一个好处,相当于期望风险最小

朴素贝叶斯算法及实现

1.朴素贝叶斯算法介绍 一个待分类项x=(a,b,c...),判断x属于y1,y2,y3...类别中的哪一类. 贝叶斯公式: 算法定义如下: (1).设x={a1, a2, a3, ...}为一个待分类项,而a1, a2, a3...分别为x的特征 (2).有类别集合C={y1, y2,  y3,  ..} (3).计算p(y1|x), p(y2|x), p(y3|x), .... (4).如果p(y(k)|x)=max{p(y1|x), p(y2|x), p(y3|x), ....},则x属于

朴素贝叶斯算法资料整理和PHP 实现版本

朴素贝叶斯算法简洁 http://blog.csdn.net/xlinsist/article/details/51236454 引言 先前曾经看了一篇文章,一个老外程序员写了一些很牛的Shell脚本,包括晚下班自动给老婆发短信啊,自动冲Coffee啊,自动扫描一个DBA发来的邮件啊, 等等.于是我也想用自己所学来做一点有趣的事情.我的想法如下: 首先我写个scrapy脚本来抓取某个网站上的笑话 之后写个Shell脚本每天早上6点自动抓取最新的笑话 然后用朴素贝叶斯模型来判断当前的笑话是否属于成

C#编程实现朴素贝叶斯算法下的情感分析

C#编程实现 这篇文章做了什么 朴素贝叶斯算法是机器学习中非常重要的分类算法,用途十分广泛,如垃圾邮件处理等.而情感分析(Sentiment Analysis)是自然语言处理(Natural Language Progressing)中的重要问题,用以对文本进行正负面的判断,以及情感度评分和意见挖掘.本文借助朴素贝叶斯算法,针对文本正负面进行判别,并且利用C#进行编程实现. 不先介绍点基础? 朴素贝叶斯,真的很朴素 朴素贝叶斯分类算法,是一种有监督学习算法,通过对训练集的学习,基于先验概率与贝叶

【数据挖掘】朴素贝叶斯算法计算ROC曲线的面积

题记:          近来关于数据挖掘学习过程中,学习到朴素贝叶斯运算ROC曲线.也是本节实验课题,roc曲线的计算原理以及如果统计TP.FP.TN.FN.TPR.FPR.ROC面积等等.往往运用ROC面积评估模型准确率,一般认为越接近0.5,模型准确率越低,最好状态接近1,完全正确的模型面积为1.下面进行展开介绍: ROC曲线的面积计算原理 一.朴素贝叶斯法的工作过程框架图 二.利用weka工具,找到训练的预处理数据 1.利用朴素贝叶斯算法对weather.nominal.arff文件进行

数据挖掘|朴素贝叶斯算法

作者:张一 链接:https://zhuanlan.zhihu.com/p/21571692 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 因为后期的项目将涉及到各种各样的价格数据处理问题,所以我们现在开始学习一些简单的数据清洗与算法的知识.关于算法,以前听起来觉得好高大上,现在开始学,觉得书上的描述并不是很通俗易懂,所以用自己的语言来简要写一下这些算法~ 注:非商业转载注明作者即可,商业转载请联系作者授权并支付稿费.本人已授权"维权骑士"网站(ht

朴素贝叶斯算法原理及实现

朴素贝叶斯算法简单高效,在处理分类问题上,是应该首先考虑的方法之一. 1.准备知识 贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类. 这个定理解决了现实生活里经常遇到的问题:已知某条件概率,如何得到两个事件交换后的概率,也就是在已知P(A|B)的情况下如何求得P(B|A).这里先解释什么是条件概率: 表示事件B已经发生的前提下,事件A发生的概率,叫做事件B发生下事件A的条件概率.其基本求解公式为:. 下面不加证明地直接给出贝叶斯定理: 2.朴素贝叶斯分类 2.1

朴素贝叶斯算法(Naive Bayes)

朴素贝叶斯算法(Naive Bayes) 阅读目录 一.病人分类的例子 二.朴素贝叶斯分类器的公式 三.账号分类的例子 四.性别分类的例子 生活中很多场合需要用到分类,比如新闻分类.病人分类等等. 本文介绍朴素贝叶斯分类器(Naive Bayes classifier),它是一种简单有效的常用分类算法. 回到顶部 一.病人分类的例子 让我从一个例子开始讲起,你会看到贝叶斯分类器很好懂,一点都不难. 某个医院早上收了六个门诊病人,如下表. 症状 职业 疾病 打喷嚏 护士 感冒  打喷嚏 农夫 过敏