机器学习实战学习笔记(三)分类—朴素贝叶斯(python3实现)

来源:互联网 发布:linux vi 显示行数 编辑:程序博客网 时间:2024/06/09 19:10

概述

朴素贝叶斯是贝叶斯决策理论的一部分,贝叶斯决策的核心在于选择具有最高概率的决策。使用朴素贝叶斯进行分类的优势在于适用于数据不充分的情况,也能进行多种分类,

但是对输入数据的准备方式非常敏感,只适用于标称型数据。需要注意的是,朴素贝叶斯之所以“朴素”,是因为它假设了特征之间相互独立,即特征之间不会相互影响(朴素贝叶斯还有另外一个假设,就是所有特征同等重要。这两个假设都很难在实际情况中做到,但对我们分类的影响没有想象的那么大。

准备工作

条件概率和条件概率的计算方式(贝叶斯准则)(略。。。)

算法实现(基于贝努利模型,不考虑出现次数)

众所周知,朴素贝叶斯的一般应用多为文本分类,可以在算法应用于文本分类的过程中对算法的流程和实现进一步说明

0.问题描述

在线社区屏蔽侮辱性言论

1.准备数据:从文本中构建词向量

2.载入实验样本,python3代码:

"""方法返回经过切分且去除标点的词条向量和每个词条向量人工标注的侮辱性or非侮辱性"""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
"""方法统计所有在文档中出现的单词输入:词条向量矩阵输出:列表形式的出现词汇表"""def createVocabList(dataSet):    vocabSet=set([])    for document in dataSet:        vocabSet=vocabSet|set(document)    return list(vocabSet)


a.词集模型:统计每个单词某单词是否出现

"""方法将单个词条向量转换成与词汇表等长的1 0向量(词集模型)输入:词汇表和词条向量输出:词汇表等长的向量(0/1)"""def setOfWords2Vec(vocabList,inputSet):    returnVec=[0]*len(vocabList)    for word in inputSet:        if word in vocabList:            returnVec[vocabList.index(word)]=1        else:            print("word %s is not in the vocabulary!" % word)    return  returnVec

b.词袋模型:统计每个单词出现的次数

"""朴素贝叶斯词袋模型"""def bagofWords2VecMN(vocabList,inputSet):    returnVec=[0]*len(vocabList)    for word in inputSet:        if word in vocabList:            returnVec[vocabList.index(word)]+=1    return returnVec

3.从词向量计算概率

"""朴素贝叶斯分类器训练函数输入:文档矩阵,每篇文档类别标签所构成的向量输出:在给定类别下各个单词出现的概率,文档属于侮辱类的概率"""def trainNBO_0(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

4.测试算法:结合实际修改分类器

a.为了避免概率相乘时有因数值为0的情况发生,可以将算有所有词的出现数初始化为1,而将分母初始化为2

b.下溢出问题,多个数值较小的概率相乘,容易得出0结果(四舍五入),可以对这些概率取对数

"""修改后的朴素贝叶斯分类器训练函数"""def trainNBO_1(trainMatrix,trainCategory):    numTrainDocs=len(trainMatrix)    numWords=len(trainMatrix[0])    pAbusive=sum(trainCategory)/float(numTrainDocs)    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=log(p1Num/p1Denom)    p0Vect=log(p0Num/p0Denom)    return p0Vect,p1Vect,pAbusive

5.集成各个模块并测试,python3代码如下:

"""朴素贝叶斯分类函数输入:要分类的向量,使用trainNBO_1计算得到的概率输出:类别"""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    else:        return 0"""封装所有的操作,使其简单"""def testingNB():    listOPosts,listClasses=loadDataSet()    myVocabList=createVocabList(listOPosts)    trainMat=[]    for postinDoc in listOPosts:        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))    poV,p1V,pAb=trainNBO_1(array(trainMat),array(listClasses))    testEntry=['love','my','dalmation']    thisDoc=array(setOfWords2Vec(myVocabList,testEntry))    print(testEntry,"classified as: ",classifyNB(thisDoc,poV,p1V,pAb))    testEntry=['stupid','gardage']    thisDoc=array(setOfWords2Vec(myVocabList,testEntry))    print(testEntry,"classified as: ",classifyNB(thisDoc,poV,p1V,pAb))

示例:使用朴素贝叶斯对垃圾邮件进行分类

1.准备数据:切分文本

结合已有的数据信息,找出最容易应用已有贝叶斯算法的数据处理方式,根据示例数据,给出文本解析python3代码:

"""将邮件中乱七八糟的内容切分转换成词的列表"""def textParse(bigString):    import re    listOfTokens=re.split(r'\W*',bigString)    return [tok.lower() for tok in listOfTokens if len(tok)>2]

2.测试算法:使用朴素贝叶斯进行交叉验证

留存交叉验证:随机选择一部分数据作为测试集,剩余部分作为训练集的过程。直至如此多次迭代求出平均错误率。测试的python3代码如下:

"""垃圾邮件分类器的训练与测试"""def spamTest():    docList=[]    classList=[]    fullText=[]    #导入文件下的文本文件,解析使之成为词列表    for i in range(1,26):        wordList=textParse(open('email/spam/%d.txt' %i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(1)        wordList=textParse(open('email/ham/%d.txt' %i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(0)    #留存交叉验证,选择十个文件作为测试集,并删除之,其余构成训练集    vocabList=createVocabList(docList)    trainingSet=range(50)    testSet=[]    j=50    for i in range(10):        randIndex=int(random.uniform(0,j))        testSet.append(trainingSet[randIndex])        trainingSet=list(trainingSet)        del(trainingSet[randIndex])        j=j-1    trainMat=[]    trainClasses=[]    for docIndex in trainingSet:        trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))        trainClasses.append(classList[docIndex])    p0V,p1V,pSpam=trainNBO_1(array(trainMat),array(trainClasses))    errorCount=0    #对测试集分类并计算错误率    for docIndex in testSet:        wordVector=setOfWords2Vec(vocabList,docList[docIndex])        if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:            errorCount+=1    print("the error rate is : ",float(errorCount)/len(testSet))

小结

贝叶斯概率和贝叶斯准则提供了一种利用已知值来估计未知概率的有效方法,尽管朴素贝叶斯的假设存在一些问题,但是其在多数情况下的分类效果还是非常理想的。




阅读全文
0 0
原创粉丝点击