朴素贝叶斯(naive bayes)

朴素贝叶斯(naive bayes)

主要参考资料:《机器学习实战》《统计学习方法》


1.朴素贝叶斯分类原理

朴素贝叶斯法是基于贝叶斯定理特征条件独立假设(称为朴素的原因)的分类方法。先看看维基百科中贝叶斯定理的描述:

贝叶斯定理(维基百科)

通常,事件A在事件B(发生)的条件下的概率,与事件B在事件A的条件下的概率是不一样的;然而,这两者是有确定的关系,贝叶斯定理就是这种关系的陈述。

公式描述如下:

P(A|B)=P(A|B)P(A)P(B)

其中P(A|B)是在B发生的情况下A发生的可能性。

在机器学习中,常常用事件A表示属于某个类别,事件B表示特征条件的集合。以下图作为例子讲解:

图中共有两类点,记为c1和c2。p(ci|x,y)表示点(x,y)为类ci的概率,那么根据贝叶斯公式,可以进行如下分类:

  • 如果P(c1|x,y)>P(c2|x,y),则断定该点属于c1
  • 如果P(c1|x,y)<P(c2|x,y),则断定该点属于c2

如果用P(x,y|ci)表示类ci中点(x,y)的概率(分布),则:

P(ci|x,y)=P(x,y|ci)P(ci)P(x,y)

又由于假设了特征条件独立,即x和y之间没有任何的关系,则:

P(ci|x,y)=P(x|ci)P(y|ci)P(ci)P(x,y)

分母相同,只需要比较分子即可。朴素贝叶斯算法训练的目的就是得到训练集中P(x|ci)P(y|ci)P(ci),即不同独立特征的条件概率

2.朴素贝叶斯实现

2.1准备数据

由于是简单的示例,直接创建训练集和类标签向量:

# 训练集:留言板的中的留言
def create_data_set():
    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‘]]
    classVec = [0,1,0,1,0,1]    #1表示侮辱性语句, 0表示文明用语
    return postingList,classVec

当前数据集中的数据是单词,我们要根据单词出现的频率估计出条件概率,就必须知道每个单词出现的频数,而统计单词频数,首先得创建单词表,即所有单词只出现一次的列表(集合):

#创建单词表
def create_vocablist(dataSet):
    vocabSet = set([])  #create empty set
    for document in dataSet:
        vocabSet = vocabSet | set(document) #取并集
    return list(vocabSet)

有了单词表就可以将语句转化为频率矢量,首先将单词表所有单词的频率初始化为0,然后遍历每一条语句,将出现的单词频率置为1(0表示未出现该单词,1表示出现该单词):

#将输入语句转化为单词频率向量,表示单词表中的哪些单词出现过
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else: print "the word: %s is not in my Vocabulary!" % word
    return returnVec

利用上面生成的数据集生成一个单词表,结果如下:

将语句”I buying cute dog”转化为向量如下:

2.2训练算法

先看看训练的目标参数:P(w1|ci),P(w2|ci),...,P(wm|ci)P(ci),其中wi表示某一个单词,因为一条语句是由若干单词组成,且我们假设每个单词出现的事件是独立的,故类ci有语句w的概率P(w? |ci)=P(w1|ci),P(w2|ci),...,P(wm|ci)。

训练函数传入的参数有两个,分别是语句集合转化的单词表向量集合和类标签向量。首先根据类标签列表可以计算出侮辱性语句和非侮辱性语句的频率,然后再计算各个特征的条件概率。

计算特征的条件概率时使用了numpy中的矢量运算,极大的简化了程序的编写。先定义2个空的单词表矢量,用来统计侮辱性单词和非侮辱性单词的频数,再定义2个浮点型变量,用来统计侮辱性单词和非侮辱性单词的总数。遍历单词表向量集合,根据每个向量的类别,统计侮辱性和非侮辱性单词的频数与总数。最后,将频数除以总数,就可以得到侮辱性或非侮辱性条件下某单词的出现的概率。

#朴素贝叶斯训练函数,输入为所有文档的单词频率向量集合,类标签向量
def trainNB(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix) #文档数量
    numWords = len(trainMatrix[0]) #单词表长度
    pAbusive = sum(trainCategory)/float(numTrainDocs) #侮辱性词语的频率
    p0Num = zeros(numWords); p1Num = zeros(numWords) #分子初始化为0
    p0Denom = 0.0; p1Denom = 0.0                   #分母初始化为0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1: #如果是侮辱性语句
            p1Num += trainMatrix[i] #矢量相加,将侮辱性语句中出现的词语频率全部加1
            p1Denom += sum(trainMatrix[i]) #屈辱性词语的总量也增加
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect = p1Num/p1Denom #对每个元素做除法
    p0Vect = p0Num/p0Denom
    return p0Vect,p1Vect,pAbusive #返回所有词语非侮辱性词语中的频率,所有词语在侮辱性词语中的频率,侮辱性语句的频率

但是这段程序有两个问题,问题一为可能发生下溢出,问题二为某语句的某个单词在侮辱性或非侮辱性集合中的频率为0,这会导致连乘的积为0.

首先解决问题一:

频率都是很小的小数,这些小数连乘的结果最终也是非常小非常小的小数,在计算机中会发生下溢出或者为0,总之都不是正确的结果。较为常见的解决方法是使用对数,将连乘变为连加。相应的程序修改如下:

p1Vect = log(p1Num/p1Denom) #变为对数,防止下溢出;对每个元素做除法
p0Vect = log(p0Num/p0Denom)

然后解决问题二:

可以通过分子全部初始化为1,分母初始化为2解决该问题,这种方法在统计学中叫做贝叶斯估计

条件概率P(wj|ci)的极大似然估计为:

P(wj|ci)=∑I(wj,ci)I(ci)

我们原先就是按照上面的公式计算P(wj|ci),但是该公式可能出现所要估计的概率值为0的情况,所以给分子分母增加一项,称为条件概率的贝叶斯估计,具体如下:

P(wj|ci)=∑I(wj,ci)+λI(ci)+Sjλ

其中λ>0,Sj表示wj可以取得不同值的个数。当λ=1时,称为拉普拉斯平滑

在我们所讨论的问题中,wj表示某个单词是否出现,只有0和1两个值,故Sj=2,所以初始化时分子为1,分母为2,再根据遍历结果增加分子和分母的值。相应的程序修改如下:

p0Num = ones(numWords); p1Num = ones(numWords) #分子初始化为1
p0Denom = 2.0; p1Denom = 2.0                   #分母初始化为2

2.3测试算法

根据以下准则编写分类函数:

  • 如果P(c0|x,y)>P(c1|x,y),则断定为非侮辱性语句
  • 如果P(c0|x,y)<P(c1|x,y),则断定为侮辱性语句
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify * p1Vec) + log(pClass1) #矢量相乘求出概率,log相加
    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else:
        return 0

然后编写测试函数,进行测试,需要注意的是python中的列表不提供矢量运算,要想进行矢量运算,就要将列表转化为numpy中的array或者mat

def testingNB():
    listOPosts,listClasses = create_data_set()
    myVocabList = create_vocablist(listOPosts)
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB(array(trainMat),array(listClasses))
    testEntry = [‘love‘, ‘my‘, ‘dalmation‘]
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print testEntry,‘classified as: ‘,classifyNB(thisDoc,p0V,p1V,pAb)
    testEntry = [‘stupid‘, ‘garbage‘]
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print testEntry,‘classified as: ‘,classifyNB(thisDoc,p0V,p1V,pAb)

运行结果如下:

3.总结

  • 源码在我的GitHub中,MachineLearningAction仓库里面有常见的机器学习算法处理常见数据集的各种实例,欢迎访问
  • 朴素贝叶斯算法核心就两个:
    • 贝叶斯定理
    • 朴素:假设各个特征之间是独立的
  • 只要牢记朴素贝叶斯的核心以及公式,那么编写程序就比较容易
  • 朴素贝叶斯常常用于文本分类,然而该方法对于英文等语言很好用,对中文就不是很好,因为中文是字组成词,对于长句子要进行“分词”操作,比如“黄金”和“金黄”的字完全一样,但是意思截然不同
  • 朴素贝叶斯有很多的改进方法,比如说用词袋模型代替词集模型,移除停用词
时间: 2024-10-05 06:46:27

朴素贝叶斯(naive bayes)的相关文章

NLP系列(2)_用朴素贝叶斯进行文本分类(上)

作者:寒小阳 && 龙心尘 时间:2016年1月. 出处:http://blog.csdn.net/longxinchen_ml/article/details/50597149 http://blog.csdn.net/han_xiaoyang/article/details/50616559 声明:版权全部,转载请联系作者并注明出处 1. 引言 贝叶斯方法是一个历史悠久.有着坚实的理论基础的方法,同一时候处理非常多问题时直接而又高效.非常多高级自然语言处理模型也能够从它演化而来.因此,

Step by Step 改进朴素贝叶斯算法

引言 如果你对naive bayes认识还处于初级阶段,只了解基本的原理和假设,还没有实现过产品级的代码,那么这篇文章能够帮助你一步步对原始的朴素贝叶斯算法进行改进.在这个过程中你将会看到朴素贝叶斯假设的一些不合理处以及局限性,从而了解为什么这些假设在简化你的算法的同时,使最终分类结果变得糟糕,并针对这些问题提出了改进的方法. 朴素贝叶斯(Naive Bayes) 出处: <机器学习>(Machine Learning by Tom M.Mitchell) 符号和术语 假设待分类的实例 X 可

统计学习方法 李航---第4章 朴素贝叶斯法

第4章 朴素贝叶斯法 朴素贝叶斯 (naive Bayes) 法是基于贝叶斯定理与特征条件独立假设的分类方法.对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布:然后基于此模型,对给定的输入x,利用贝叶斯定理求出后验概率最大的输出Y. 4.1 朴素贝叶斯法的学习与分类 基本方法 朴素贝叶斯法通过训练数据集学习X和Y的联合概率分布 P(X,Y). 具体地,学习以 下先验概率分布及条件概率分布. 先验概率分布 条件概率分布 条件概率分布有指数级数量的参数,其估计实际是不可行的

斯坦福机器学习实现与分析之六(朴素贝叶斯)

朴素贝叶斯(Naive Bayes)适用于离散特征的分类问题,对于连续问题则需将特征离散化后使用.朴素贝叶斯有多元伯努利事件模型和多项式事件模型,在伯努利事件模型中,特征每一维的值只能是0或1,而多项式模型中特征每一维的值可取0到N之间的整数,因此伯努利模型是多项式模型的一种特例,下面的推导就直接使用伯努利模型. 朴素贝叶斯原理推导 与GDA类似,朴素贝叶斯对一个测试样本分类时,通过比较p(y=0|x)和p(y=1|x)来进行决策.根据贝叶斯公式: \( \begin{aligned} p(y=

斯坦福CS229机器学习课程笔记四:GDA、朴素贝叶斯、多项事件模型

生成学习与判别学习 像逻辑回归,用hθ(x) = g(θTx) 直接地来建模 p(y|x; θ) :或者像感知机,直接从输入空间映射到输出空间(0或1),它们都被称作判别学习(discriminative learning).与之相对的是生成学习(generative learning),先对 p(x|y) 与 p(y) 建模,然后通过贝叶斯法则导出后验条件概率分布分母的计算规则为全概率公式:p(x) = p(x|y = 1)p(y = 1) + p(x|y =0)p(y = 0).这一节介绍的

统计学习四:1.朴素贝叶斯

全文引用自<统计学习方法>(李航) 朴素贝叶斯(naive Bayes)法 是以贝叶斯定理为基础的一中分类方法,它的前提条件是假设特征条件相互独立.对于给定的训练集,它首先基于特征条件假设的前提条件,去学习输入与输出的条件概率分布,然后根据此分布模型,对给定的输入x,利用贝叶斯定理求出后验概率最大的输出y. 1.朴素贝叶斯的学习与分类 1.1 基本方法 假设输入空间\(X \subseteq R^n\)为n维向量的集合,输入空间为类标记集合\(Y=\{c_1,c_2,\cdots,c_K\}\

朴素贝叶斯算法小结

朴素贝叶斯naive bayes是直接生成方法,也就是直接找出特征输出Y和特征X的联合分布P(X,Y)P(X,Y),然后用P(Y|X)=P(X,Y)/P(X)P(Y|X)=P(X,Y)/P(X)得出. 数学基础: 1. 最大似然估计 原文地址:https://www.cnblogs.com/guodavid/p/10169867.html

朴素贝叶斯-垃圾邮件分类实现

1. 前言 <朴素贝叶斯算法(Naive Bayes)>,介绍了朴素贝叶斯原理.本文介绍的是朴素贝叶斯的基础实现,用来垃圾邮件分类. 2. 朴素贝叶斯基础实现 朴素贝叶斯 (naive Bayes) 法是基于贝叶斯定理与特征条件独立假设的分类的方法.对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布:然后基于此模型,对于给定的输入$x$,利用贝叶斯定理求出后验概率最大的输出$y$,完整代码GitHub. 输入: #垃圾邮件的内容 posting_list = [ ['m

朴素贝叶斯(Naive Bayes)及Python实现

朴素贝叶斯(Naive Bayes)及Python实现 http://www.cnblogs.com/sumai 1.模型 在GDA 中,我们要求特征向量 x 是连续实数向量.如果 x 是离散值的话,可以考虑采用朴素贝叶斯的分类方法. 以垃圾邮件分类为例子,采用最简单的特征描述方法,首先找一部英语词典,将里面的单词全部列出来.然后将每封邮件表示成一个向量,向量中每一维都是字典中的一个词的 0/1值,1 表示该词在邮件中出现,0 表示未出现. 比如一封邮件中出现了“ a”和“ buy”,没有出现“