朴素贝叶斯分类

来源:互联网 发布:协同过滤推荐算法研究 编辑:程序博客网 时间:2024/06/06 03:29

一、朴素贝叶斯分类原理

看了两篇介绍很详细的博文http://blog.csdn.net/pkueecser/article/details/8184299,http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html

以下是综合精简的笔记。

1.核心思想:选择高概率对应的类别


2.数学基础:贝叶斯定理

             

3.分类原理

为一个待分类项,而每个a为x的一个特征属性,类别集合为

计算

 如果,则

4.假设

  特征之间相互独立

  每个特征同等重要

5.如何计算

a)找到一个已知分类的待分类项集合,这个集合叫做训练样本集。

b)统计得到在各类别下各个特征属性的条件概率估计。即 

      

c)如果各个特征属性是条件独立的,则根据贝叶斯定理有如下推导:

       

d)因为分母对于所有类别为常数,因为我们只要将分子最大化皆可。又因为各特征属性是条件独立的,所以有:

     

6.可能出现的问题

a)问题:的计算

   特征属性为离散值时:统计训练样本中各个划分在每个类别中出现的频率,即在类别  中  出现的次数

  特征属性为连续值时:

         通常假定其值服从高斯分布(也称正态分布)。即:

           

           而

         因此只要计算出训练样本中各个类别中此特征项划分的各均值和标准差,代入上述公式即可得到需要的估计值。

b) 问题:若某个类别下某个特征属性从来没出现过,则会导致, 则会使预测不准

     laplace平滑 ----就是对每个类别下所有特征的计数加1,即为 

    (出现次数+1) / (a1出现次数+1+a2出现次数+1+...+am出现次数+1)=(出现次数+1) / (出现次数+m)

c) 问题:概率求积很可能遇到浮点数溢出的情况,

    把求积转换成求和,只需要对贝叶斯公式中分子求log即可(log(a*b) = log(a) + log(b)

7.优缺点

  优点:在数据较少的情况下仍然有效,可以处理多类别问题

  缺点:该分类方法假设属性之间相互独立,这个假设在实际应用中往往是不成立的(可以考虑用聚类算法先将相关性较大的属性聚类),这给模型的正确分                 类带来了一定影响。在属性个数比较多或者属性之间相关性较大时,分类效率比不上决策树模型。而在属性相关性较小时,性能最为良好。

二、使用案例-----文档的自动分类

两种模型:

1.多项式模型

先验概率P(c)= 类c下单词总数/整个训练样本的单词总数

类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)

V是训练样本的单词表(即抽取单词,单词出现多次,只算一个),|V|则表示训练样本包含多少种单词。

2.伯努利模型

P(c)= 类c下文件总数/整个训练样本的文件总数

P(tk|c)=(类c下包含单词tk的文件数+1)/(类c下单词总数+2)

实现代码:

#naive_bayes.pyfrom 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,classVec#创建一个包含在所有文档中出现的不重复词的词汇表表def CreatVolList(dataset):    volLst=set([]);    for data in dataset:        volLst=volLst|set(data) #求集合的并集    return list(volLst)#某个文档对应于词汇表的向量(词集模式)#伯努利模型:若出现,则为1,不出现则为0def WordsToVec1(volLst,inputset):    vec=[0]*len(volLst)    for volc in inputset:        if volc in volLst:            vec[volLst.index(volc)]=1    return vec#某个文档对应于词汇表的向量(词袋模式)#多项式模型:若出现,则为1,不出现则为0def WordsToVec2(volLst,inputset):    vec=[0]*len(volLst)    for volc in inputset:        if volc in volLst:            vec[volLst.index(volc)]+=1    return vec#训练算法:从词向量计算概率def TrainNB0(trainMatrix,trainCategory):  #trainMatrix训练文档集合的向量组成的矩阵,trainCategory每个训练文档的类别组成的向量    numTrainDocs=len(trainMatrix)         #文档总个数    numWors=len(trainMatrix[0])           #词汇表中的词汇个数    #计算每个类别的概率    pAbuse= sum(trainCategory)/float(numTrainDocs)#侮辱性文档1的概率(非侮辱性文档0概率为(1-侮辱性文档的概率))    #计算每个类别下不同特征的条件概率P(tk|c)=(类c下包含单词tk的文件数+1)/(类c下单词总数+2)    p0Num=ones(numWors); p0Denom=2.0     #初始化分子分母,laplace平滑    p1Num=ones(numWors); p1Denom=2.0    for i in range(numTrainDocs):        if trainCategory[i]==1:           #若属于1类            p1Num+=trainMatrix[i]         #分子            p1Denom+=sum(trainMatrix[i])  #分母        else:                             #若属于0类            p0Num+=trainMatrix[i]              p0Denom+=sum(trainMatrix[i])    p0=log(p0Num/p0Denom)                 #条件概率取log,防止下溢    p1=log(p1Num/p1Denom)    return pAbuse,p0,p1#测试算法:朴素贝叶斯分类函数def ClassifyNB(testVec,p0Vec,p1Vec,pClass1):  #arg max log(P(yi))+sum(log(P(aj|yi)))    p0=sum(testVec*p0Vec)+(1-pClass1)             p1=sum(testVec*p1Vec)+pClass1    if p0<p1:        return 1    else:        return 0#进行预测def TestNB():    lst,cls=LoadDataSet()    myVol=CreatVolList(lst)    trainMat=[]    for vec in lst:        trainMat.append(WordsToVec(myVol,vec))    pA,p0,p1=TrainNB0(trainMat,cls)    testEntry1=['love','my','dalmation']    testVec1=array(WordsToVec1(myVol,testEntry1))    class1=ClassifyNB(testVec1,p0,p1,pA)    print ("answer of testEntry1 is: ",class1)    testEntry2=['stupid','garbage']    testVec2=array(WordsToVec1(myVol,testEntry2))    class2=ClassifyNB(testVec2,p0,p1,pA)    print ("answer of testEntry2 is: ",class2)       if __name__=="__main__":    from naive_bayes import *    TestNB()

三、使用案例-----过滤垃圾邮件

#准备数据:切分文本def TextParse(bigString):    import re    lstOfTokens=re.split(r'\W*',bigString)    return [tok.lower() for tok in lstOfTokens if len(tok)>0]#垃圾邮件测试函数def SpamTest():    docList=[]; classList = []; fullText =[]    for i in range(1,26):        wordList = TextParse(open('G://程序//python//3.朴素贝叶斯//email//spam//%d.txt' % i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(1)        wordList = TextParse(open('G://程序//python//3.朴素贝叶斯//email//ham//%d.txt' % i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(0)    vocabList = CreatVolList(docList)     #创建词汇表    trainingSet = range(50); testSet=[]   #创建训练集,测试集    for i in range(10):                           randIndex = int(random.uniform(0,len(trainingSet)))        testSet.append(trainingSet[randIndex])        del(trainingSet[randIndex])      trainMat=[]; trainClasses = []    for docIndex in trainingSet:        trainMat.append(WordsToVec2(vocabList, docList[docIndex]))        trainClasses.append(classList[docIndex])    p0V,p1V,pSpam = TrainNB0(array(trainMat),array(trainClasses))    errorCount = 0    for docIndex in testSet:                wordVector = WordsToVec2(vocabList, docList[docIndex])        if ClassifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:            errorCount += 1            print ("classification error",docList[docIndex])    print ('the error rate is: ',float(errorCount)/len(testSet))if __name__=='__main__':    import spam    spam.SpamTest()




      




0 0