分类问题之朴素贝叶斯模型

简介

朴素贝叶斯模型(Naive Bayes)是一种基于贝叶斯决策理论的分类方法。其核心思想就是选择具有最高概率的决策。如果用p1(x)表示特征向量x对应数据属于类别1的概率,用p2(x)表示特征向量x对应数据属于类别2的概率,那么可以利用下面的规则来判断它的类别:
- 如果p1(x) > p2(x), 那么类别为1。
- 如果p2(x) > p1(x), 那么类别为2。
也就是说,我们更倾向于选择高概率对应的类别。

条件概率

条件概率:事件A在事件B已经发生的条件下发生的概率,记作p(A|B),读作”在B条件下A的概率”。
计算方法:p(A|B) = p(AB)/p(B)
简单推导:由p(A|B) = p(AB)/p(B) [结论1],不难推出p(B|A) = p(AB)/p(A) [结论2],综合结论1和结论2,推出:p(A|B) = p(B|A)*p(A)/p(B)
p(A|B) = p(B|A)*p(A)/p(B)是一个非常神奇的公式,它表示除了”在B条件下A的概率”与”在A条件下B的概率”之间的关系,而朴素贝叶斯分类模型算法的核心就是基于这个关系

分类模型

那么,如何利用训练样本集以及条件概率来构造朴素贝叶斯模型呢?
机器学习的一个重要应用就是文档的自动分类。在文档分类中,整个文档(如一封电子邮件)是实例,而电子邮件中的某些元素则构成特征。如果你是一个QQ邮箱用户,当你打开你的QQ邮箱的垃圾箱的时候你会发现,垃圾箱里面有很多邮件并不是你手动删除的,而是被自动分类到了垃圾邮箱中。这就是一个简单、经典的文档分类问题的场景。
简单来讲,我们可以通过观察文档中出现的词,并把每个词出现或不出现(或者出现次数)作为一个特征,这样得到的特征数目就会跟词汇表中的词目一样多。朴素贝叶斯就是文档分类问题的常用算法。
朴素的含义:假设词汇表中共有1000个词,那么特征向量x就是1000维的。由统计学知,如果每个特征需要N个样本,那么对于10个特征将需要N^10个样本,对于包含1000个特征的词汇表将需要N^1000个样本,这种情况下我们是不可能完成模型构建的。但是,如果假设特征之间相互独立:即一个特征(单词)是否出现或者出现的可能性与它和其他单词没有任何约束关系。举个例子,假设单词bacon出现在unhealthy后面和出现在delicious后面的概率相同(当然我们知道这种假设并不正确,bacon经常出现在delicious附近,而很少出现在unhealthy附近)。这个假设正是朴素贝叶斯分类器中朴素(naive)一词的含义。
A bit consciously naive, don’t you think?

接下来,我们开始展开构造朴素贝叶斯模型。
符号定义:c表示分类,x表示特征。在二分类问题中ci(1<=i<=2)表示分类i。xi(1<=i<=n)表示特征i的值,其中n表示特征数,xi为1表示文档中出现了词汇表的第i个单词;反之,0表示文档中没有出现词汇表的第i个单词。
由前面基于条件概率公式推导出来的关系,可得:p(ci|x) = p(x|ci)*p(ci)/p(x)
其中:
- p(ci|x)表示特征向量是类别ci概率
- p(x|ci)表示训练样本中ci类别中出现特征向量x的概率,如果将x展开为一个个堵路的特征,那么就可以等价写作p(x0,x1,x2,…,xn|ci),这里假设所有次都独立,这就意味着可以使用p(x0|ci)*p(x1|ci)*p(x2|ci)*…*p(xn|ci)
- p(ci)表示训练样本中一个样例是cile类别的概率
- p(x)表示一个文档的特殊向量为x的概率
上述4个概率中,p(x)是不同类别公用的计算因子(分母),不影响计算结果因此不需要计算。其他3个,都可以通过对训练样本简单的统计计算得出。
那么,特征向量x所属为ck,满足:p(ck|x) = max{p(x|ci)*p(ci)}, 1<=i<=2

python代码实现

#!/usr/bin/python
#encoding=utf-8
'''
@author: slowalker
@date: 2015-06-07
'''
from 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'],
                   ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                   ['stop', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    #每个文本数据对应的分类
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec

#词集模型(set-of-words model):创建一个包含在所有文档中国年出现的不重复词的列表
def createVocabList(dataSet):
    vocabSet = set([])
    for document in dataSet:
        vocabSet = vocabSet | set(document)
    return list(vocabSet)

#根基词汇表和输入文本,计算输入文本对应的文档向量
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList) #python中list的*运算表示将list中的元素重复复制若干次
    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

#训练模型
def trainNB0(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    #计算分类为1的概率
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    #拉普拉斯平滑
    p0Num = ones(numWords)
    p1Num = ones(numWords)
    p0Denom = 2.0
    p1Denom = 2.0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    #避免由于太多很小的数相乘造成乘法计算的下溢出,等价转化成对于的加法计算。
    p1Vect = log(p1Num / p1Denom)
    p0Vect = log(p0Num / p0Denom)
    return p0Vect, p1Vect, pAbusive

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    #避免由于太多很小的数相乘造成乘法计算的下溢出,等价转化成对于的加法计算。
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)
    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else:
        return 0

if __name__ == '__main__':
    listOPosts, listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat = []
    for postInDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postInDoc))
    p0V, p1V, pAb = trainNB0(trainMat, listClasses)
    #查看模型训练的参数结果
    #print pAb #后验概率
    #print p0V #条件概率
    #print p1V #条件概率
    #构造数据集测试模型效果
    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)

参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值