美文网首页
朴素贝叶斯笔记(1)

朴素贝叶斯笔记(1)

作者: omuraisu | 来源:发表于2017-09-14 11:00 被阅读0次

    朴素贝叶斯(Naive Bayes)是一种简单的分类算法,它的经典应用案例为人所熟知:文本分类(如垃圾邮件过滤)。
    优点:在数据较少的情况下仍然有效,可以处理多类别问题
    缺点:对于输入数据的准备方式较为敏感。
    适用数据类型:标称型数据(即离散型数据,变量的结果只在有限目标集中取值)

    贝叶斯决策理论核心思想:选择高概率对应的类别。
    例:p1(x,y)表示(x,y)属于类别1的概率, p2(x,y)表示(x,y)属于类别2的概率。如果p1>p2,则类别为1。如果p2>p1,则类别为2

    假设y为类别,x为测试数据,那么贝叶斯分类器就是一个求p(y|x)的过程。

    image.png

    P(y)就是在不知道数据是类别为y的概率,这个数值可以通过计算训练集中属于特定类别的样本比例来得到。
    假设F1,F2为训练集数据的特征,C为一种类别,P(x)就是每个特征的概率P(F1,F2)。这可以通过计算训练集中含有特定特征值的样本比例来得到。
    比较微妙的部分是计算P(x|y),即P(F1,F2|C)。这个值的意义为:如果知道样本的类别为C,那么有多大的可能性可以看到特征值F1,F2。

    在概率论中我们还知道:
    P(F1,F2|C)=P(F1|C)P(F2|C,F1)
    在这里我们假设F1,F2相互独立,那么就可以把P(F2|C,F1)简化成P(F2|C)

    最终我们得到的公式为:

    最终推导出、公式.png

    对于每个类别的结果,其分母的P(F1,F2)都是一样的值,因此可以简单忽略,这并不会改变最终胜出的类别。也就是说我们只要求到p(C)和p(F1|C) p(F2|C)就可以得到p(C|F1,F2)

    接下来我们使用朴素贝叶斯进行文档分类。

    准备数据:

    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为侮辱性文字,0为正常言论
        return postingList,classVec
    

    从训练集中创建词汇表:

    def createVocabList(dataSet):
        vocabList=set([])#set方法用于创建集合
        for document in dataSet:
            vocabList=vocabList|set(document)
            # |用于求两个集合的并集,最终得到不重复词表。
        return list(vocabList)
    

    将文档向量化

    #vocabList为词汇表 inputSet为输入文本
    def setOfWords2Vec(vocabList,inputSet):
        returnVec=[0]*len(vocabList)
        for word in inputSet:
            if word in vocabList:
                returnVec[vocabList.index(word)]+=1
        return returnVec
    

    训练函数:

    #trainMatrix为向量化后的文档矩阵
    #trainCategory为每篇文档类别标签构成的列表,即第一个函数中的classVec
    def trainNB0(trainMatrix,trainCategory): #训练函数
        numTrainDocs=len(trainMatrix) #文档矩阵所含文档数量,即训练集数据数量
        numWords=len(trainMatrix[0]) #数据的特征值数量
        pAbusive=sum(trainCategory)/float(numTrainDocs) 
        #计算任意文档属于侮辱性文档(class=1)的概率。即p(1)。p(0)=1-p(1),也就是公式中的p(y)
        p0Num=np.ones(numWords)
        p1Num=np.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=sp.log(p1Num/p1Denom) #对每个元素做除法
        #p0Vect,p1Vect为给定文档类别条件下词汇表中单词的出现概率
        p0Vect=sp.log(p0Num/p0Denom)
        return p0Vect,p1Vect,pAbusive
    
    

    朴素贝叶斯分类函数:

    def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):#测试函数
        p1=sum(vec2Classify*p1Vec)+sp.log(pClass1)
        p0=sum(vec2Classify*p0Vec)+sp.log(1.0-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=setOfWords2Vec(myVocabList,testEntry)
        print testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb)
        testEntry=['stupid','garbage']
        thisDoc=np.array(setOfWords2Vec(myVocabList,testEntry))
        print testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb)
    

    现在我们分类器已经构建好。下面我们使用该分类器来过滤垃圾邮件。

    切分文章单词函数:

    def textParse(bigString):
        import re
        listOfTokens=re.split(r'\W*',bigString)
        #以任意非字母的字符作为分隔符。
        return [tok.lower()for tok in listOfTokens if len(tok)>2]
        #将单词小写化,并过滤掉小于两个字符的单词。
    

    垃圾邮件分类函数:

    import random
    def spamTest():
        docList=[]; classList=[];fullText=[]
        for i in range(1,26):
            wordList=textParse(open('C:\Users\Lenovo\Desktop\Data\machinelearninginaction\Ch04\email\spam\%d.txt' %i).read())
            docList.append(wordList)
            fullText.extend(wordList)#在fullText末尾扩展添加wordList
            classList.append(1)
            wordList=textParse(open('C:\Users\Lenovo\Desktop\Data\machinelearninginaction\Ch04\email\ham\%d.txt' %i).read())
            docList.append(wordList)
            fullText.extend(wordList)
            classList.append(0)
        vocabList=createVocabList(docList)
        trainingSet=range(50);testSet=[]
        for i in range(10):
            randIndex=int(random.uniform(0,len(trainingSet)))
            #uniform函数生成0到trainingSet长度之间的一个浮点数。
            testSet.append(trainingSet[randIndex])
            del(trainingSet[randIndex])
        trainMat=[];trainClasses=[]
        for docIndex in trainingSet:
            trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
            trainClasses.append(classList[docIndex])
        p0V,p1V,pSpam=trainNB0(np.array(trainMat),np.array(trainClasses))
        errorCount=0
        for docIndex in testSet:
            wordVector=setOfWords2Vec(vocabList,docList[docIndex])
            if classifyNB(np.array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
                errorCount+=1
        print 'the error rate is: ',float(errorCount)/len(testSet)
    
    spamTest()     
    
    

    随机选择数据的一部分作为训练集,
    而剩余部分作为测试集的过程称为留存交叉验证
    函数spamTest()会输出在10封随机选择的电子邮件上的分类错误率。既然这些电子邮件是随机选择的,所以每次的输出结果可能有些差别。

    相关文章

      网友评论

          本文标题:朴素贝叶斯笔记(1)

          本文链接:https://www.haomeiwen.com/subject/pqbrsxtx.html