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

总说

都知道条件概率吧:

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, p0

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))
    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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值