机器学习基础--贝叶斯分类器

来源:互联网 发布:xss攻击 java 编辑:程序博客网 时间:2024/06/04 23:53

单纯的贝叶斯分类器很简单,基本上就是一个贝叶斯公式,要理解透彻贝叶斯分类器需要搞清楚两个概念

似然函数

基本上维基百科讲的很清楚,我这里在重复一下,可以直接去维基百科看
在数理统计学中,似然函数是一种关于统计模型中的参数的函数,表示模型参数中的似然性。似然函数在统计推断中有重大作用,如在最大似然估计和费雪信息之中的应用等等。“似然性”与“或然性”或“概率”意思相近,都是指某种事件发生的可能性,但是在统计学中,“似然性”和“或然性”或“概率”又有明确的区分。概率用于在已知一些参数的情况下,预测接下来的观测所得到的结果,而似然性则是用于在已知某些观测所得到的结果时,对有关事物的性质的参数进行估计。

在这种意义上,似然函数可以理解为条件概率的逆反。在已知某个参数B时,事件A会发生的概率写作:

P(AB)=P(A,B)P(B)

利用贝叶斯定理,

P(BA)=P(AB)P(B)P(A)

因此,我们可以反过来构造表示似然性的方法:已知有事件A发生,运用似然函数L(BA),我们估计参数B的可能性。形式上,似然函数也是一种条件概率函数,但我们关注的变量改变了:

bP(AB=b)

注意到这里并不要求似然函数满足归一性: bBP(AB=b)=1。一个似然函数乘以一个正的常数之后仍然是似然函数。对所有α>0,都可以有似然函数:

L(bA)=αP(AB=b)

例子

考虑投掷一枚硬币的实验。通常来说,已知投出的硬币正面朝上和反面朝上的概率各自是 pH=0.5,便可以知道投掷若干次后出现各种结果的可能性。比如说,投两次都是正面朝上的概率是0.25。用条件概率表示,就是:

P(HHpH=0.5)=0.52=0.25

其中H表示正面朝上。

在统计学中,我们关心的是在已知一系列投掷的结果时,关于硬币投掷时正面朝上的可能性的信息。
我们可以建立一个统计模型:假设硬币投出时会有 pH的概率正面朝上,而有1pH的概率反面朝上。
这时,条件概率可以改写成似然函数:

L(pHHH)=P(HHpH=0.5)=0.25

也就是说,对于取定的似然函数,在观测到两次投掷都是正面朝上时, pH=0.5 的似然性是0.25(这并不表示当观测到两次正面朝上时pH=0.5的概率是0.25)。

如果考虑 pH=0.6,那么似然函数的值也会改变。

L(pHHH)=P(HHpH=0.6)=0.36

三次投掷中头两次正面朝上,第三次反面朝上时的似然函数

注意到似然函数的值变大了。

这说明,如果参数 pH的取值变成0.6的话,结果观测到连续两次正面朝上的概率要比假设 pH=0.5时更大。也就是说,参数 pH取成0.6要比取成0.5更有说服力,更为“合理”。总之,似然函数的重要性不是它的具体取值,而是当参数变化时函数到底变小还是变大。对同一个似然函数,如果存在一个参数值,使得它的函数值达到最大的话,那么这个值就是最为“合理”的参数值。

在这个例子中,似然函数实际上等于:

L(θHH)=P(HHpH=θ)=θ2,其中0pH1

如果取pH=1,那么似然函数达到最大值1。也就是说,当连续观测到两次正面朝上时,假设硬币投掷时正面朝上的概率为1是最合理的。

类似地,如果观测到的是三次投掷硬币,头两次正面朝上,第三次反面朝上,那么似然函数将会是:

L(θHHT)=P(HHTpH=θ)=θ2(1θ),其中T表示反面朝上, 0pH1

这时候,似然函数的最大值将会在pH=23的时候取到。也就是说,当观测到三次投掷中前两次正面朝上而后一次反面朝上时,估计硬币投掷时正面朝上的概率 pH=23是最合理的。

最大似然估计

我们首先要定义似然函数:

lik(θ)=fD(x1,,xnθ)

并且在θ的所有取值上通过令一阶导数等于零,使这个函数取到最大值。这个使可能性最大的 θˆ值即称为 θ 的最大似然估计

例子

现在假设例子1中的盒子中有无数个硬币,对于0p1中的任何一个p, 都有一个抛出正面概率为 p的硬币对应,我们来求其似然函数的最大值:

lik(θ)=fD(H=49,T=80-49p)=(8049)p49(1p)31

其中 0p1. 我们可以使用微分法来求最值。方程两边同时对 p 取微分,并使其为零。

0==ddp((8049)p49(1p)31)49p48(1p)3131p49(1p)30p48(1p)30[49(1p)31p]

在不同比例参数值下一个二项式过程的可能性曲线t = 3, n = 10;其最大似然估计值发生在其众数并在曲线的最大值处。

其解为p=0, p=1,以及 p=49/80.使可能性最大的解显然是 p=49/80(因为p=0p=1这两个解会使可能性为零)。因此我们说最大似然估计值为 pˆ=49/80pˆ.

这个结果很容易一般化。只需要用一个字母t 代替49用以表达伯努利试验中的被观察数据(即样本)的“成功”次数,用另一个字母 n 代表伯努利试验的次数即可。使用完全同样的方法即可以得到最大似然估计值:

pˆ=tn

对于任何成功次数为 t,试验总数为 n的伯努利试验。

基本上就是似然函数就是一件事发生的概率公式,而最大似然估计是在当前似然函数下函数能取到的最大值,就是一件事最可能发生的概率,这在计算中很重要。

在一个垃圾邮件检测代码中贝叶斯公式的解释

P(BA)=P(AB)P(B)P(A)

P(B) 表示邮件是垃圾邮件的概率 垃圾邮件数/总邮件数
P(A) 表示某个词在所有邮件中的出现概率 /
P(AB) 是垃圾邮件的情况下某个词出现的概率 是垃圾邮件某词出现次数/是垃圾邮件所有词数目
P(BA) 在一个词出现概率为A的情况下是垃圾邮件的概率 所有出现词的概率求和 对比垃圾邮件和非垃圾邮件那个值更大 判断是否是垃圾邮件

这里有个优化就是对词的初始出现次数默认置1,防止分子为0导致整个值为0,还有所有词数如果为0的话默认置2,防止除0错误
另一个是为了优化多个0.1左右的值乘积会变得很小,所以用ln(ab)=ln(a)+ln(b)这个公式可以把乘积变成先ln然后求和

看一个机器学习实战中贝叶斯检测垃圾词的代码

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'],                 ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]    classVec = [0,1,0,1,0,1]    #1 is abusive, 0 not    return postingList,classVecdef createVocabList(dataSet):    vocabSet = set([])  #create empty set    for document in dataSet:        vocabSet = vocabSet | set(document) #union of the two sets    return list(vocabSet)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 returnVecdef trainNB0(trainMatrix,trainCategory):    numTrainDocs = len(trainMatrix)    numWords = len(trainMatrix[0])    pAbusive = sum(trainCategory)/float(numTrainDocs)    p0Num = ones(numWords); p1Num = ones(numWords)      #change to ones()     p0Denom = 2.0; p1Denom = 2.0                        #change to 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)          #change to log()    p0Vect = log(p0Num/p0Denom)          #change to log()    return p0Vect,p1Vect,pAbusivedef classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):    p1 = sum(vec2Classify * p1Vec) + log(pClass1)    #element-wise mult    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)    if p1 > p0:        return 1    else:         return 0def testingNB():    listOPosts,listClasses = loadDataSet()    myVocabList = createVocabList(listOPosts)    trainMat=[]    for postinDoc in listOPosts:        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))    p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))    testEntry = ['love', 'my', 'dalmation']    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))    print "p0v: ", p0V, " p1V : ", p1V, " pAb: ", pAb    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)if __name__ == '__main__':    listOposts, listClasses = loadDataSet()    myVocabList = createVocabList(listOposts)    print setOfWords2Vec(myVocabList, listOposts[0])    print testingNB()