贝叶斯定理

简述

贝叶斯定理用数学的方法来解释生活中大家都知道的常识

形式最简单的定理往往是最好的定理,比如说中心极限定理,这样的定理往往会成为某一个领域的理论基础。机器学习的各种算法中使用的方法,最常见的就是贝叶斯定理。下面我用一个小例子来推出贝叶斯定理:

已知:有N个苹果,和M个梨子,苹果为黄色的概率为20%,梨子为黄色的概率为80%
:假如我在这堆水果中观察到了一个黄色的水果,问这个水果是梨子的概率是多少。

用数学的语言来表达,就是已知
P(apple) = N / (N + M),P(pear) = M / (N + M),P(yellow|apple) = 0.2, P(yellow|pear) = 0.8
P(pear|yellow).

要想得到这个答案,我们需要
1. 要求出全部水果中为黄色的水果数目
2. 求出黄色的梨子数目

对于*(1)*我们可以得到 P(yellow) * (N + M), P(yellow) = p(apple) \* P(yellow|apple) + P(pear) \* p(yellow|pear)

对于*(2)*我们可以得到 P(yellow|pear) \* M

(2) / (1) 可得:

P(pear|yellow) = P(yellow|pear) * p(pear) / [P(apple) * P(yellow|apple) + P(pear) * P(yellow|pear)]

化简可得:P(pear|yellow) = P(yellow,pear) / P(yellow), 用简单的话来表示就是在已知是黄色的,能推出是梨子的概率P(pear|yellow)是黄色的梨子占全部水果的概率P(yellow,pear)除上水果颜色是黄色的概率P(yellow). 这个公式很简单吧。

我们将梨子代换为A,黄色代换为B公式可以写成:P(A|B) = P(A,B) / P(B), 可得

P(A,B) = P(A|B) * P(B)

贝叶斯公式就这样推出来了。
贝叶斯公式

本文的一个大概的思路:先讲一讲我概括出的一个基本的贝叶斯学习框架,然后再举几个简单的例子说明这些框架,最后再举出一个复杂一点的例子,也都是以贝叶斯机器学习框架中的模块来讲解

朴素贝叶斯算法

  • 朴素:特征条件独立
  • 贝叶斯:基于贝叶斯定理

概述

根据贝叶斯定理,对一个分类问题,给定样本特征x,样本属于类别y的概率是 

在这里,x是一个特征向量,将设x维度为M。因为朴素的假设,即特征条件独立,根据全概率公式展开,公式(1)可以表达

这里,只要分别估计出,特征Xi
在每一类的条件概率就可以了。类别y的先验概率可以通过训练集算出,同样通过训练集上的统计,可以得出对应每一类上的,条件独立的特征对应的条件概率向量。 如何统计,就是下一部分所关心的内容。

学习(参数估计)

下面介绍如何从数据中,学习得到朴素贝叶斯分类模型。概述分类方法,并提出一个值得注意的问题。

经过上述步骤,我们就得到了模型的基本概率,也就完成了学习的任务。

分类

通过学到的概率,给定未分类新实例X,就可以通过上述概率进行计算,得到该实例属于各类的后验概率p(y=ck|X),因为对所有的类来说,公式*(2)*中分母的值都相同,所以只计算分子部分即可,具体步骤如下

于是我们得到了新实例的分类结果

拉普拉斯平滑

到这里好像方法已经介绍完了,实则有一个小问题需要注意,在公式(3)(4)中,如果从样本中算出的概率值为0该怎么办呢?
下面介绍一种简单方法,给学习步骤中的两个概率计算公式,分子和分母都分别加上一个常数,就可以避免这个问题。更新过后的公式如下

则避免了0概率问题,这种方法被称为拉普拉斯平滑

算法思想和流程

给定的训练集是标定了 侮辱性/非侮辱性 的句子(因为是英语句子,所以基本视分词为已经解决的问题,如果是汉语,则要先进行分词),我们认为特征就是句子中的单个词语。单个词语有极性表征,整个句子所包含的单词的极性表征就是句子的极性。
由以上的基础,应用朴素贝叶斯分类,就变成了这样的问题
1. 初始化步,构建可以表征句子的特征向量(词汇表)。并根据这个特征向量,把训练集表征出来。从训练集中分离部分数据作为测试集。
1. 学习步,计算类的先验概率和特征向量对应每一类的条件概率向量
1. 分类步, 计算测试集中待分类句子在每一类的分类后验概率,取最大值作为其分类,并与给定标签比较,得到误分类率。

Python 实现

  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    
def createVocabList(dataSet):#创建词汇表
    vocabSet = set([])
    for document in dataSet:
        vocabSet = vocabSet | set(document) #创建并集
    return list(vocabSet)
def bagOfWord2VecMN(vocabList,inputSet):#根据词汇表,讲句子转化为向量
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
    return returnVec
  1. 训练:
def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    pAbusive = sum(trainCategory)/float(numTrainDocs)
    p0Num = ones(numWords);p1Num = ones(numWords)#计算频数初始化为1
    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-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(trainMat,listClasses)#训练
    #测试
    testEntry = ['love','my','dalmation']
    thisDoc = setOfWords2Vec(myVocabList,testEntry)
    print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)



处身寒夜,把握星光。