【机器学习】朴素贝叶斯-对文档进行分类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuanzhe117/article/details/79077223

  上一篇文章【机器学习】朴素贝叶斯-条件概率  

  已经提过了利用朴素贝叶斯进行文档分类的步骤,下面我们来看每个步骤的目的,搞清楚我们要处理的数据满足什么条件,是什么格式,我们所写的每一个函数的入参是什么,处理完成后的出参,即处理结果是什么样的,又是如何将计算的条件概率应用于贝叶斯公式,得到文档所属的类型。

 

  一篇文档属于侮辱性文档还是非侮辱性文档,是根据文档内容判断的,文档由单词构成,判断一篇文档是什么类型也就是判断文档中这些单词出现的情况下,文档属于什么类型,每个单词都看做一个独立特征的话(事实上可能并不是独立的,这里就是用到了朴素贝叶斯假设,假设所有词都是互相独立的,即条件独立性假设,这样一来接下来的事都好办了),这篇文档就有多个特征,特征数就是单词的数量。我们用下面的公式计算条件概率P(w|ci),进而求条件概率P(ci|w) 

  P(w|ci)=P(w0,w1,w2..wn|ci)=P(w0|ci)P(w1|ci)P(w2|ci)…P(wn|ci)

 

  首先,分词:文档-->

  我们使用Pythonstring.split()方法进行分词,并依赖正则表达式处理特殊要求,如空格以及大小写转换。这里的样本数据集为6个已知类别的文档,每个文档均已被分好词。

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','worthlsess','dog','food','stupid']
    ]
    classVec=[0,1,0,1,0,1] #0代表正常言论,1代表侮辱性文字
    return postingList,classVec

  然后,构建词向量:词-->词向量

扫描二维码关注公众号,回复: 3816706 查看本文章

  我们有一些样本数据,把样本数据中包含的文档作为全集,可以构建一个词全集,这个词全集是不重复的词列表,我们把样本都转换成词列表长度的向量,用10分别表示本文档中存在/不存在词列表对应位置的单词。以后要对某个新的文档进行分类,我们把新文档中的词和词列表比对,也构建同样的向量,该向量就是词向量。

def createVocabList(dataSet):
    vocabSet = set([])
    for document in dataSet:
        vocabSet = vocabSet | set(document)
    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 returnVec

  第三,计算条件概率

  词向量一步巧妙的转换,词没有办法计算,将词转换成数字就可以计算了!样本文档是已知分类的,按照分类,分别计算侮辱性文档和非侮辱性文档中各单词出现的频数,除以该类的总词数,得到各单词的条件概率。

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
    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
    return p0Vect,p1Vect,pAbusive

  

  运行结果:


  第四,分类函数

  有了前面的公式,将各概率带入公式即可求得某文档属于各个类别的概率,从而判定属于哪个类别。但有些实际问题,比如,相乘的这些概率P(w0|ci)P(w1|ci)P(w2|ci),他们的值大多都非常小,所以程序会下溢出或者结果被四舍五入后得到0,这都不是我们想要的。一个比较好的办法是对乘积取自然对数。

 

  P(c1|w) = P(w|c1)*P(c1)/P(w)

  P(c0|w) = P(w|c0)*P(c0)/P(w)


  要比较P(c1|w)P(c0|w)的大小,因为分母P(w)相同,所以只需比较 P(w|c1)*P(c1)P(w|c0)*P(c0)的大小。分别取对数后,P(w|c1)*P(c1)变成了lnP(w|c1)+ lnP(c1),同理,P(w|c0)*P(c0)变成了lnP(w|c0)+ lnP(c0)。还记得前面的P(w|ci)=P(w0|ci)P(w1|ci)P(w2|ci)…P(wn|ci)吗?

代入后,lnP(w|c1)+ lnP(c1)变成了ln (P(w0|c1)P(w1|c1)P(w2|c1)…P(wn|c1))+ lnP(c1),继续利用对数的性质,得到了ln P(w0|c1) + ln P(w1|c1) +…+P(wn|c1))+ lnP(c1)

 

  干脆,我们把上面的概率计算结果直接取对数,改为:

p1Vect=log(p1Num/p1Denom)
p0Vect=log(p0Num/p0Denom)

  这样,某文档属于各个类别的概率就可以由如下函数求得:

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    p1 = sum(vec2Classify*p1Vec) + log(pClass1)
    p0 = sum(vec2Classify*p0Vec) + log(pClass1)
    if p1>p0:
        return 1
    else:
        return 0
     第五,测试

  写了一个测试函数,给文档进行分类。

def testingNB():
    listOPosts,listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat = []
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB0(trainMat,listClasses)

    testEntry = ['love','my','dalmation']
    thisDoc = array(setOfWords2Vec(myVocabList,testEntry))
    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)

  运行结果:


  所以,['love','my','dalmation']这篇文档属于非侮辱性文档,['stupid','garbage']这篇文档属于侮辱性文档。分类显然是正确的。


猜你喜欢

转载自blog.csdn.net/zhuanzhe117/article/details/79077223