4.机器学习实战之朴素贝叶斯

返回目录

上一篇:决策树

1. 简单理论介绍

1.1  贝叶斯定理

了解贝叶斯定理之前,需要先了解下条件概率。P(A|B)表示在事件B已经发生的条件下事件A发生的概率:

P(A|B)=P(AB)  P(B)daf
afdfd

假如我们已经知道了P(A|B),但是现在我们想要求P(B|A),也就是在事件A发生的条件下事件B发生的概率,这时贝叶斯定理就派上用场了。

P(B|A)=P(A|B)P(B)  P(A)daf
afdfd

1.2  朴素贝叶斯分类原理

朴素贝叶斯分类是以贝叶斯定理为基础的,之所以称为“朴素”,是因为整个过程只做最原始、最简单的假设。假设我们现在有一个训练数据集,该数据集的特征向量为,n表示特征的个数,同时也有该数据集的类别标签向量,s表示类别的个数,现在就是要计算,i=[0,s-1],也就是说根据现有的这些特征来计算它所属类别标签中的每个类别的概率,最后取概率最大的分类标签为结果。那么如何计算呢?由贝叶斯定理可得:

假设特征之间互相独立,则:

由于分母P(w)的值都一样,所以只需计算分子就可以了,即:

接下来我们用一个例子来说明下朴素贝叶斯分类原理,该例子来源于阮一峰的《朴素贝叶斯分类器的应用》。根据某社区网站的抽

样统计,该站10000个账号中有89%为真实账号(设为C0),11%为虚假账号(设为C1),P(C0)=0.89,P(C1)=0.11。

接下来,就要用统计资料判断一个账号的真实性。假定某一个账号有以下三个特征:

W0: 日志数量/注册天数
W1: 好友数量/注册天数
W2: 是否使用真实头像(真实头像为1,非真实头像为0)

W0 = 0.1
W1 = 0.2
W2 = 0

根据上面的三个特征去判断这个账号是否真实。

方法是计算P(W0|C=0)P(W1|C=0)P(W2|C=0)P(C=0)P(W0|C=1)P(W1|C=1)P(W2|C=1)P(C=1)的值,如果前者大,说明为真实账

号,否则为虚假账号。

虽然上面这些值可以从统计资料得到,但是这里有一个问题:W0和W1是连续变量,不适宜按照某个特定值计算概率。一个技巧是

将连续值变为离散值,计算区间的概率。比如将W0分解成[0, 0.05]、(0.05, 0.2)、[0.2, +∞]三个区间,然后计算每个区间的概率。在

我们这个例子中,W0等于0.1,落在第二个区间,所以计算的时候,就使用第二个区间的发生概率。

P(W0|C=0) = 0.5, P(W0|C=1) = 0.1
P(W1|C=0) = 0.7, P(W1|C=1) = 0.2
P(W2|C=0) = 0.2, P(W2|C=1) = 0.9

因此:

P(W0|C=0)P(W1|C=0)P(W2|C=0)P(C=0)
		= 0.5 x 0.7 x 0.2 x 0.89
		= 0.0623

P(W0|C=1)P(W1|C=1)P(W2|C=1)P(C=1)
		= 0.1 x 0.2 x 0.9 x 0.11
		= 0.00198

可以看到,虽然这个用户没有使用真实头像,但是他是真实账号的概率,比虚假账号高出30多倍,因此判断这个账号为真。

1.3  朴素贝叶斯分类的优缺点

优点:计算简单,在数据量很大时计算速度很快

缺点:假设特征之间是相互独立的

2. 文本向量

在本篇文章中我们想要使用朴素贝叶斯分类器来将留言板上的留言内容分为两类:侮辱性言论和正常言论,分别用1和0来表示。但是这儿有一个问题就是,如何让计算机出识别这些文本呢?这时我们可以考虑将文本转换成文本向量。文本向量其实就是特征向量。

我们先来了解几个概念,我们将留言板上的每一条留言内容称为文档,而文档(在这里指每一条留言内容)是由词条组成的,词条的是指字符的任意组合,在这里你可以将它认为是单词,同时我们将所有留言内容称为文档库。关系如下图:

现在我们要构建文本向量,在这儿就是将文档(一条留言内容)转换为一个向量。有两种构建方法:词集模型(set-of-words model)和词袋模型(bag-of-words model)。

2.1 词集模型

我们先介绍词集模型。首先我们需要从文档库(即所有的留言内容中)找到所有的词条(单词),将这些单词称为词汇表。如果要对某一文档构建文本向量,首先先创建一个长度为词汇表长度的向量,该向量的每一个元素为1或0,1代表词汇表中的词条在该文档(一条留言内容)中出现过,0则相反。例如,词汇表为{‘my’,‘name‘,‘is’,‘tom‘,‘and‘,‘home’,‘is’,‘Beijing’,‘am‘,‘bag’,‘ok’},某一条留言内容为“my
name is tom,and my home is Beijing”,将它转为文本向量就是[1,1,1,1,1,1,1,1,0,0,0],文本向量前8个元素为1表示词库表中的前8个词条在该留言内容中出现过,后3个元素为0表示词库表中的最后3个词条在该留言内容中未出现过。注意,虽然,“my”这个词条在该留言内容中出现过两次,但是我们仍然只记为1。也就是说词集模型中向量的元素内容表示词条是否在词汇表中出现过。

2.2  词袋模型

现在来介绍下词袋模型,词袋模型中向量的元素内容表示词条出现在词汇表中的次数。例如上面的“my”,出现两次,如果用词袋模型表示,则文本向量为[2,1,1,1,1,1,1,1,0,0,0]。一般来说使用词袋模型的效果会更好一些。

3. 代码实现

3.1 准备数据

# 准备数据
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']]
    classVec = [0,1,0,1,0,1]    #1代表侮辱性言论,0代表正常言论
    return postingList,classVec

3.2 创建词汇表

# 创建词汇表
def createVocabList(dataSet):
    vocabSet = set([])  #create empty set
    for document in dataSet:
        vocabSet = vocabSet | set(document) #创建两个集合的并集
    return list(vocabSet)

3.3 构建文本向量

# 词集模型文本向量
# vocabList:词汇表,inputSet:文本内容
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0]*len(vocabList)# 创建一个长度为词汇表长度的集合
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1#出现就赋值为1
        else: print "the word: %s is not in my Vocabulary!" % word
    return returnVec

# 词库模型文本向量
def bagOfWords2VecMN(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1#出现一次就将次数加1
        else: print "the word: %s is not in my Vocabulary!" % word
    return returnVec

测试上面的效果:

listOppsts,listClasses = loadDataSet()
myVocabList = createVocabList(listOppsts)
print '词汇表:',myVocabList
print '词集模型向量:',setOfWords2Vec(myVocabList,listOppsts[0])#将第一条留言内容转成词集模型向量
print '词袋模型向量:',bagOfWords2VecMN(myVocabList,listOppsts[0])#将第一条留言内容转成词袋模型向量

运行结果:

词汇表: ['cute', 'love', 'help', 'garbage', 'quit', 'I', 'problems', 'is', 'park', 'stop', 'flea', 'dalmation', 'licks', 'food', 'not', 'him', 'buying', 'posting', 'has', 'worthless', 'ate', 'to', 'maybe', 'please', 'dog', 'how', 'stupid', 'so', 'take', 'mr', 'steak', 'my']
词集模型向量: [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1]
词袋模型向量: [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1]

3.4  训练算法:文本向量计算概率

我们已经得到了特征向量(即文本向量),现在要做的是根据这些特征向量去计算每个类别下各个特征的概率,类似于我们上面例子中从统计资料中得到概率这一过程。

import numpy as np

# 从训练文档的特征向量中计算各个类别下特征的概率
# trainMatrix:训练文档的特征向量(MxN),trainCategory:训练文档的类别标签(1xM)
# M表示训练集的个数,N表示词汇表长度,也就是特征个数
def trainNB0(trainMatrix,trainCategory):
    m = len(trainMatrix)# 训练文档的个数
    n = len(trainMatrix[0])# 词汇表长度,也就是词条的个数,也就是特征个数。

    p0Num = np.zeros(n); p1Num = np.zeros(n)      #change to ones()
    p0Denom = 0.0; p1Denom = 0.0                        #change to 2.0
    for i in range(m):
        if trainCategory[i] == 1:#类别为侮辱性言论
            p1Num += trainMatrix[i]#得到一个向量,该向量元素的值为词汇表中的每个词条在侮辱性言论(c=1)类别里出现的次数
            p1Denom += sum(trainMatrix[i])#得到侮辱性言论类别词条出现的总数
        else:# 类别为正常言论
            p0Num += trainMatrix[i]#同上
            p0Denom += sum(trainMatrix[i])#同上

    p1Vect = p1Num/p1Denom#计算在侮辱性言论类别下每个词条出现的概率,p1Vect是一个向量,向量的元素为P(w=0|c=1),P(w=1|c=1),...,P(w=n|c=1)
    p0Vect = p0Num/p0Denom

    pAbusive = sum(trainCategory)/float(m)# 计算侮辱性言论文档在整个训练文档中出现的概率,即P(c=1)

    return p0Vect,p1Vect,pAbusive

测试下上面方法的效果:

listOppsts,listClasses = loadDataSet()
myVocabList = createVocabList(listOppsts)#得到词汇表

trainMat = []#创建一个空列表
for postinDoc in listOppsts:
    trainMat.append(setOfWords2Vec(myVocabList,postinDoc))#将每一个文档(每一个评论内容)转为文本向量,并存入trainMat中

p0V,p1V,pAb = trainNB0(trainMat,listClasses)#训练分类器,得到p0V,p1V,pAb
print 'P(c=1):',pAb
print 'p(w|c=1):',p1V
print 'p(w|c=0):',p0V

运行结果:

P(c=1): 0.5
p(w|c=1): [ 0.          0.          0.          0.05263158  0.05263158  0.          0.
  0.          0.05263158  0.05263158  0.          0.          0.
  0.05263158  0.05263158  0.05263158  0.05263158  0.05263158  0.
  0.10526316  0.          0.05263158  0.05263158  0.          0.10526316
  0.          0.15789474  0.          0.05263158  0.          0.          0.        ]
p(w|c=0): [ 0.04166667  0.04166667  0.04166667  0.          0.          0.04166667
  0.04166667  0.04166667  0.          0.04166667  0.04166667  0.04166667
  0.04166667  0.          0.          0.08333333  0.          0.
  0.04166667  0.          0.04166667  0.04166667  0.          0.04166667
  0.04166667  0.04166667  0.          0.04166667  0.          0.04166667
  0.04166667  0.125     ]

P(c=1)的值为0.5,表示所有留言内容中有一半的留言内容是侮辱性言论,查看下我们创建的训练集,发现该值是正确的。词汇表中第一个词条是“cute”,在类别1中没有出现过,在类别0中出现过1次,对应的条件概率是0和0.04166667,说明计算正确。

3.5 改进分类器

利用朴素贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某类别的概率,即计算,如果其中的一个概率为0,那么乘积也为0,为降低这种影响,可以将所有词条出现的次数初始化为1,并将分母初始化为2。另一个要解决的问题是下溢出。由于计算乘积时,每个概率值都比较小,所以很可能溢出,可以考虑使用对数来解决。在代数中有In(a*b)
= In(a) + In(b)。修改后的分类器代码如下:

import numpy as np

# 从训练文档的特征向量中计算各个类别下特征的概率
# trainMatrix:训练文档的特征向量(MxN),trainCategory:训练文档的类别标签(1xM)
# M表示训练集的个数,N表示词汇表长度,也就是特征个数
def trainNB0(trainMatrix,trainCategory):
    m = len(trainMatrix)# 训练文档的个数
    n = len(trainMatrix[0])# 词汇表长度,也就是词条的个数,也就是特征个数。

    <span style="color:#CC0000;">p0Num = np.ones(n); p1Num = np.ones(n)</span>      #change to ones()
    p0Denom = 2.0; p1Denom = 2.0                        #change to 2.0
    for i in range(m):
        if trainCategory[i] == 1:#类别为侮辱性言论
            p1Num += trainMatrix[i]#得到一个向量,该向量元素的值为词汇表中的每个词条在侮辱性言论(c=1)类别里出现的次数
            p1Denom += sum(trainMatrix[i])#得到侮辱性言论类别词条出现的总数
        else:# 类别为正常言论
            p0Num += trainMatrix[i]#同上
            p0Denom += sum(trainMatrix[i])#同上

    <span style="color:#CC0000;">p1Vect = np.log(p1Num/p1Denom)</span>#计算在侮辱性言论类别下每个词条出现的概率,p1Vect是一个向量,向量的每个元素表示P(w=0|c=1),P(w=1|c=1),...,P(w=n|c=1)
    <span style="color:#CC0000;">p0Vect = np.log(p0Num/p0Denom)</span>#p0Vect向量的每个元素表示P(w=0|c=0),P(w=1|c=0),...,P(w=n|c=0)

    pAbusive = sum(trainCategory)/float(m)# 计算侮辱性言论文档在整个训练文档中出现的概率,即P(c=1)

    return p0Vect,p1Vect,pAbusive

3.6  使用分类器进行分类

# 朴素贝叶斯分类器
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify * p1Vec) + np.log(pClass1)    #element-wise mult
    p0 = sum(vec2Classify * p0Vec) + np.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:#得到文档集的所有文本向量
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))

    testEntry = ['love', 'my', 'dalmation']
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)

    testEntry = ['stupid', 'garbage']
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)

测试结果:

testingNB()

运行结果:

['love', 'my', 'dalmation'] classified as:  0
['stupid', 'garbage'] classified as:  1

下一篇:Logistic回归

时间: 2024-11-05 18:32:28

4.机器学习实战之朴素贝叶斯的相关文章

机器学习实战笔记--朴素贝叶斯

1 #encoding:utf-8 2 from numpy import * 3 import feedparser 4 5 #加载数据集 6 def loadDataSet(): 7 postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], 8 ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'], 9 ['my', 'dalma

机器学习笔记之朴素贝叶斯(Naive Bayes)原理

为什么叫朴素贝叶斯? 朴素是指特征条件独立:贝叶斯是指基于贝叶斯定理. $x=\frac{{-b}\pm\sqrt{b^2-4ac}}{2a}$ $p(y=c_k|x)=\dfrac{\prod_{i=1}^{M}p(x^i|y=c_k)p(y=c_k)}{\sum_kp(y=c_k)\prod_{i=1}^{M}P(x^i|y=c_k)}$....(2) $$ % MathType!MTEF!2!1!+-% feaagKart1ev2aaatCvAUfeBSjuyZL2yd9gzLbvyNv2

机器学习笔记:朴素贝叶斯方法(Naive Bayes)原理和实现

本文主要描述了朴素贝叶斯分类方法,包括模型导出和学习描述.实例部分总结了<machine learning in action>一书中展示的一个该方法用于句子感情色彩分类的程序. 方法概述 学习(参数估计) 实现:朴素贝叶斯下的文本分类 模型概述 朴素贝叶斯方法,是指 朴素:特征条件独立 贝叶斯:基于贝叶斯定理 根据贝叶斯定理,对一个分类问题,给定样本特征x,样本属于类别y的概率是 p(y|x)=p(x|y)p(y)p(x)......(1) 在这里,x是一个特征向量,将设x维度为M.因为朴素

机器学习算法:朴素贝叶斯

朴素贝叶斯(Naive Bayesian)算法的核心思想是:分别计算给定样本属于每个分类的概率,然后挑选概率最高的作为猜测结果. 假定样本有2个特征x和y,则其属于分类1的概率记作p(C1|x,y),它的值无法直接分析训练样本得出,需要利用公式间接求得. 其中p(Ci)表示训练样本中分类为Ci的概率,它等于Ci样本数除以样本总数. p(x,y)表示满足2个特征的样本概率,它等于第1特征等于x且第2特征等于y的样本数除以样本总数.可以发现p(x,y)与当前在计算哪个分类概率是无关的,因此实际计算中

机器学习之路--朴素贝叶斯

一,引言 前两章的KNN分类算法和决策树分类算法最终都是预测出实例的确定的分类结果,但是,有时候分类器会产生错误结果:本章要学的朴素贝叶斯分类算法则是给出一个最优的猜测结果,同时给出猜测的概率估计值. 1 准备知识:条件概率公式 相信学过概率论的同学对于概率论绝对不会陌生,如果一时觉得生疏,可以查阅相关资料,在这里主要是想贴出条件概率的计算公式: P(A|B)=P(A,B)/P(B)=P(B|A)*P(A)/P(B) 2 如何使用条件概率进行分类 假设这里要被分类的类别有两类,类c1和类c2,那

吴裕雄--天生自然python机器学习:使用朴素贝叶斯过滤垃圾邮件

使用朴素贝叶斯解决一些现实生活中 的问题时,需要先从文本内容得到字符串列表,然后生成词向量. 准备数据:切分文本 测试算法:使用朴素贝叶斯进行交叉验证 文件解析及完整的垃圾邮件测试函数 def createVocabList(dataSet): vocabSet = set([]) #create empty set for document in dataSet: vocabSet = vocabSet | set(document) #union of the two sets return

【机器学习模型】朴素贝叶斯

一.啥是贝叶斯公式 1.公式定义: 贝叶斯公式是由英国数学家贝叶斯发展,用来描述两个条件概率之间的关系,比如P(A|B)和P(B|A). 按照乘法法则,可以立刻导出:P(A∩B) = P(A)*P(B|A)=P(B)*P(A|B).如上公式也可变形为:P(B|A) = P(A|B)*P(B) / P(A),即为贝叶斯公式 假设B是由相互独立的事件组成的概率空间{B1,b2,...bn}.则P(A)可以用全概率公式展开:P(A)=P (A|B1)P(B1)+P(A|B2)P(B2)+..P(A|B

Spark机器学习(4):朴素贝叶斯算法

1. 贝叶斯定理 条件概率公式: 这个公式非常简单,就是计算在B发生的情况下,A发生的概率.但是很多时候,我们很容易知道P(A|B),需要计算的是P(B|A),这时就要用到贝叶斯定理: 2. 朴素贝叶斯分类 朴素贝叶斯分类的推导过程就不详述了,其流程可以简单的用一张图来表示: 举个简单的例子来说,下面这张表说明了各地区的人口构成: 这个时候如果一个黑皮肤的人走过来(一个待分类项(0,0,1)),他是来自欧美,亚洲还是非洲呢?可以根据朴素贝叶斯分类进行计算: 欧美=0.30×0.90×0.20×0

机器学习—朴素贝叶斯

机器学习-朴素贝叶斯 本文代码均来自<机器学习实战> 朴素贝叶斯的两个基本假设: 独立:一个特征出现的可能性和与它和其他特征相邻没有关系 每个特征同等重要 这段代码是以文本分类为例介绍朴素贝叶斯算法的 要从文本中获取特征,需要先拆分文本.这里的特征是来自文本的词条(token),一个词条是字符的任意组合.可以把词条想象为单词,也可以使用非单词词条,如URL.IP地址或者任意其他字符串.然后将一个文本片段表示为一个词向量,其中值为1表示词条出现,0表示词条未出现. ??以在线社区的留言板为例,为