朴素贝叶斯的原理和实现

来源:互联网 发布:java socket聊天程序 编辑:程序博客网 时间:2024/06/08 07:35

概念

朴素贝叶斯(naïveBayes)法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入x,利用贝叶斯定理求出后验概率最大的输出y。朴素贝叶斯法实现简单,学习与预测的效率都很高,是一种常用的方法。

原理

朴素贝叶斯分类的思想基础:对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,哪个最大,就认为此待分类项属于哪个类别。

朴素贝叶斯分类的定义:

1. 设x={a1, a2, …, am}为一个待分类项,而每个a为x的一个特征属性。

2. 有类别集合C={y1, y2, …, yn}。

3. 计算P(y1|x), P(y2|x), …, P(yn|x)。

4. 如果P(yk|x)=max{ P(y1|x),P(y2|x),…,P(yn|x)},则x类别为yk。

那么现在的关键就是如何计算第3步中的各个条件概率,我们可以这么做:

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

2. 统计得到在各类别下各个特征属性的条件概率估计,即:

P(a1|y1), P(a2|y1), …, P(am|y1); …;P(a1|yn), P(a2|yn), …, P(am|yn)

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


因为分母对于所有类别为常数,因为我们只要将分子最大化即可。朴素贝叶斯法对条件概率分布作了条件独立性的假设。由于这是一个较强的假设,朴素贝叶斯法也由此得名。具体地,条件独立性假设是:


到这里只要选出最大的那个P(yk|x)就是x的类别yk。

 

一些技巧

拉普拉斯平滑

利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积,若某一个概率为0,则最后的乘积也为0。为了降低这种影响,可使用拉普拉斯平滑。

在计算p(X|Y)的时候,将分子加上λ,分母加上K*λ,其中K为X可取的值的种类数量,λ=1即为拉普拉斯平滑。

此时有P(X|Y)>0,∑P(X|Y)=1。

下溢问题

多个小概率相乘可能会造成数据下溢得不到正确的答案(四舍五入后都为0)。可以对成绩取对数,即ln(a*b)=ln(a)+ln(b)。

阈值

朴素贝叶斯一个常见的应用是文本分类,如垃圾邮件分类。如果垃圾邮件被分成正常邮件我们还可以接收,但是,如果正常邮件被分成垃圾邮件,就会比较麻烦。所以,可以给这两个分类设置不同的阈值。

如spam=3,ham=1,则p(spam|x)>3p(ham|x),才认为该邮件为垃圾邮件,而p(ham|x)> p(spam|x)则是正常邮件,否则可以视为待定。

 

文本分类的例子

转自《机器学习实战》

test.py

#coding:utf-8import bayesfrom numpy import *listOposts,listClasses=bayes.loadDataSet()myVocabList=bayes.createVocabList(listOposts)print myVocabList       #生成不重复词列表print listOposts[0]     #如果出现该词,则对应列表对应位置为1,也就是该文档的特征向量print bayes.setOfWords2Vec(myVocabList,listOposts[0])trainMat=[]for postinDoc in listOposts:    trainMat.append(bayes.setOfWords2Vec(myVocabList,postinDoc))for i in range(len(trainMat)):    print trainMat[i]   #生成所有文档的特征向量p0V,p1V,pAb=bayes.trainNB0(trainMat,listClasses)print pAb               #对于所有文档类别为1的概率print p0V               #计算词列表类别为0时的概率print p1V               #计算词列表类别为1时的概率(转换为log)testEntry = ['love','love','love','love','garbage', 'my', 'dalmation']thisDoc = array(bayes.setOfWords2Vec(myVocabList, testEntry))#生成对应的特征向量print testEntry, '特征向量:',thisDocc = bayes.classifyNB(thisDoc, p0V, p1V, pAb)print "类别为",ctestEntry = ['stupid', 'garbage']thisDoc = array(bayes.setOfWords2Vec(myVocabList, testEntry))print testEntry, '特征向量:',thisDocc = bayes.classifyNB(thisDoc, p0V, p1V, pAb)print "类别为",cbayes.spamTest()#垃圾邮件分类的一个例子

bayes.py

#coding:utf-8from 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]    #对应的分类    return postingList,classVec                 def createVocabList(dataSet):#创建不重复词列表    vocabSet = set([])  #创建空集    for document in dataSet:        vocabSet = vocabSet | set(document)#合并    return list(vocabSet)#输入为词汇表及某个文档,输出为文档向量,向量元素为0或1表示,表示单词在输入文档中是否出现def setOfWords2Vec(vocabList, inputSet):    returnVec = [0]*len(vocabList)#创建元素全为0的向量    for word in inputSet:        if word in vocabList:            returnVec[vocabList.index(word)]= 1        else: print "theword: %s is not in my Vocabulary!" % word    return returnVec#输出p(x,y|c0),p(x,y|c1),p(c1)def trainNB0(trainMatrix,trainCategory):    numTrainDocs = len(trainMatrix)    numWords = len(trainMatrix[0])    pAbusive = sum(trainCategory)/float(numTrainDocs)#计算类别为1占比,多分类需要改一下。    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)    print "类别1=",p1,"类别0=",p0    if p1 > p0:        return 1    else:         return 0#文档词袋def bagOfWords2VecMN(vocabList, inputSet):    returnVec = [0]*len(vocabList)    for word in inputSet:        if word in vocabList:            returnVec[vocabList.index(word)]+= 1    return returnVec#测试分类def 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 testEntry,'classifiedas: ',classifyNB(thisDoc,p0V,p1V,pAb)    testEntry = ['stupid', 'garbage']    thisDoc =array(setOfWords2Vec(myVocabList, testEntry))    print testEntry,'classifiedas: ',classifyNB(thisDoc,p0V,p1V,pAb)def textParse(bigString):    #inputis big string, #output is word list    import re    listOfTokens = re.split(r'\W*', bigString)    return [tok.lower() for tokin listOfTokens if len(tok) > 2]     def spamTest():    docList=[]; classList = []; fullText=[]    for i in range(1,26):        wordList = textParse(open('email/spam/%d.txt'% i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(1)        wordList = textParse(open('email/ham/%d.txt'% i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(0)    vocabList = createVocabList(docList)#创建词表    trainingSet = range(50);testSet=[]           #create test set    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:#trainthe classifier (get probs) trainNB0        trainMat.append(bagOfWords2VecMN(vocabList,docList[docIndex]))       trainClasses.append(classList[docIndex])    p0V,p1V,pSpam =trainNB0(array(trainMat),array(trainClasses))    errorCount = 0    for docIndex in testSet:        #classify the remaining items        wordVector =bagOfWords2VecMN(vocabList, docList[docIndex])        if classifyNB(array(wordVector),p0V,p1V,pSpam)!= classList[docIndex]:            errorCount += 1            print "classificationerror",docList[docIndex]    print 'the error rate is: ',float(errorCount)/len(testSet)


 

原创粉丝点击