贝叶斯分类(一)-机器学习实战

来源:互联网 发布:网易云音乐 linux 1.0 编辑:程序博客网 时间:2024/05/19 16:38

总说

都知道条件概率吧:

p(c|x)=p(x|c)p(c)p(x)

贝叶斯分类类似:
p(ci|w)=p(w|ci)p(ci)p(w)

记忆方法:既然是用条件概率进行分类的,因此绝对是已知某件事情(w)发生了,然后判断这件事情属于哪一类。

拿文本分类来说:给出几个关键字,为了方便称为“句子”吧,判断这个句子是abusive还是not abusive。这个句子是有某些关键字组成的。w就是这些关键字组成的向量。c1=1, c0=0,如此一来。就是已知w,求p(1|w)p(0|w)

根据公式,我们可以利用右边的式子,如果求得p(1|w)>p(0|w),那么就认为w属于abusive.

右侧3个概率式子的处理

  1. p(w)是没有必要参与计算的,根本不影响比较关系。
  2. p(ci) 是最容易求得的。比如数据库中共有10条句子(注意:句子仍旧是指一组关键词,可以先看下面的代码),如果有4条是abusive,那么就是p(1)=4/10,p(0)=6/10;
  3. p(w|ci)=p(w0|ci)p(w2|ci)p(wn|ci),这里假设每个单词出现是独立的,不会相互影响。如何求每一个p(wj|ci)呢?

p(wj|ci)的方法

比如求p(good|c0),就是说在not abusive的句子中出现”good”单词的概率。显然就是

p(good|c0)=notabusivegoodnotabusive

有2个问题:

  • 如果一个单词在某个类别中没有出现,比如good在abusive类别中没有出现,那么计算p(good|c1)就是0,就会导致p(c1|w)=0。显然出现以偏概全的现象。
  • 由于计算p(w|ci)是连乘形式,多个小数连乘会导致下溢,导致结果不准。

解决方法:

  1. 为了防止出现概率为0的情况,直接初始化令每个单词在每个类都出现1次。同时将分母(not abusive或是abusive中所有句子的单词出现的次数总和)初始化为2,这是为了使在进行数据训练前,两种类别的概率各占一半。
  2. 利用自然对数ln.将计算出的p(wj|ci)取自然对数,相加即可。

总结

可见,我们求出的并不是真正意义上的p(ci|w),只是类似”p(w|ci)p(ci)”,值得注意的是计算p(w|ci)是初始化更改了一些东西,并且采用了ln.
另外如果一个句子中出现了多个相同的单词,在转换的vec中就不再是0和1的组合,1被替换成单词出现的次数,而不是原先的是否出现,详见代码

# -*- coding: utf-8 -*-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,classVec#主要是将dataSet中的句子全部拿出来,作为集合的一个个元素。#集合的元素具有唯一性,用  'union'或是'|'来进行集合的并。def createVocabList(dataSet):    vocabSet = set([])    for document in dataSet:        vocabSet = vocabSet | set(document)    return list(vocabSet)#inputSet是要输入的集合,如: bayes.setOfWords2Vec(myVocabList,listOPosts[0])#如果输入的集合的word在myVocabList中,则返回的returnVec的响应的位置为1#其他位置为0,通过查找vec中哪些位置为1,即可知道该句子含有哪些词def setOfWords2Vec(vocabList, inputSet):    returnVec = [0]*len(vocabList)    for word in inputSet:        if word in vocabList:            returnVec[vocabList.index(word)] = 1#           returnVec[vocabList.index(word)] += 1#           如果是一个句子中出现多个相同的单词,这种模型就是'set-of-words model 就要用+=        else: print "the word :%s is not in my Vocabulary" % word    return returnVec# Naive Bayes classfier traning function# trainMatrix的每一行是上方的returnVec,也就是说是32长度的vec,当然这里是有6行# 对于某句话,如果分类是1,那么 p1Num += trainMatrix[i]是vec的对应位置相加,# 最终p1Num是每个单词在类别1所出现的次数。 # p1Denom += sum(trainMatrix[i])是句子中出现的单词总数。最后p1Denom是所有abusive的句子# 的单词数。 因此 p1Vect = p1Num/p1Denom 就是“(每个单词出现在类别1的次数)/(类别1出现的所有句子的单词总和)”,# 得到的就是p(w1|c1),p(w2|c1),...,p(w32|c1)def trainNB0(trainMatrix,trainCategory):    numTrainDocs = len(trainMatrix)    numWords = len(trainMatrix[0])    pAbusive = sum(trainCategory)/float(numTrainDocs)#   p0Num = zeros(numWords); p1Num = zeros(numWords)#   p0Denom = 0.0; p1Denom = 0.0#   由于计算 p(w|c1) = p(w1|c1)p(w2|c1)...p(w32|c1),如果其中的一个单词并未出现在c1中,那么p(wx|c1)=0#   为了避免这种情况,因而出现次数初始化为1,分母初始化为2    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 = p1Num/p1Denom   #   p0Vect = p0Num/p0Denom #   由于小数过多的练乘,可能会得到不精确的非常小的数,因此转换为log    p1Vect = log(p1Num/p1Denom)    p0Vect = log(p0Num/p0Denom)     return p0Vect,p1Vect,pAbusive#   vec2Classify比如是[1 0 0 1 0 1 1...1],代表句子中有哪些单词。所以 vec2Classify*p1Vec就是#   每一个单词在类1中出现的概率的log,sum来讲这些概率全部乘起来。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, p1    else:        return 0, p0def 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))    calssfier,pp = classifyNB(thisDoc,p0V,p1V,pAb)    print testEntry,'value is ',pp,'classfied as: ',calssfier    testEntry = ['stupid','garbage']    thisDoc = array(setOfWords2Vec(myVocabList,testEntry))    calssfier,pp = classifyNB(thisDoc,p0V,p1V,pAb)    print testEntry,'value is ',pp, 'classfied as: ',calssfier
0 0
原创粉丝点击