美文网首页
朴素贝叶斯笔记(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