机器学习实战-朴素贝叶斯

来源:互联网 发布:知乎社区 编辑:程序博客网 时间:2024/06/05 03:31

使用python进行文本分类

# -*- coding: utf-8 -*-"""Created on Mon Aug 21 17:17:19 2017@author: rocky"""#机器学习实战第四章#朴素bayes#使用python进行文本分类#从文本中构建词向量from numpy import *def loadDataSet():#创建一个实验样本    postingList=[['my','dog','has','flea','problem','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,classVecdef createVocalList(dataSet):    vocabSet=set([])#set返回一个不含重复词的列表    for document in dataSet:        vocabSet=vocabSet|set(document)#创建两个集合的并集    return list(vocabSet)def setOfWord2Vec(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#以上的三个程序的作用:#程序1返回几篇文档和文本类别,程序2对程序1进行非重复处理并拼接,返回一篇文档#程序3的输入分别对应程序2的结果和程序1中的第i篇文档,返回的结果是2的结果的每一个词#是否出现在第i篇文章中。出现则是1,没出现则是0.#这样我们就把一篇文章(在第i篇文档环境下)转换成了一组数字

我们可以做这样的实验,在命令窗口输入以下:

listOPosts,listClasses=loadDataSet()data=[['my','dog'],['is','rain']]lis=createVocalList(data)lisOut[22]: ['rain', 'my', 'is', 'dog']setOfWord2Vec(lis,listOPosts[5])the word: quit is not in my Vocabulary!the word: buying is not in my Vocabulary!the word: worthless is not in my Vocabulary!the word: food is not in my Vocabulary!the word: stupid is not in my Vocabulary!Out[23]: [0, 0, 0, 1]

我们可以判断第六行的每个词是否出现在data中,从而得到data的数字表示,为后面对data进行概率计算(好坏属性判断)准备。

训练算法:从词向量计算概率

#训练算法:从词向量计算概率(假设二类分布,即只有两个属性)def trainNB0(trainMatrix,trainCategory):    numTrainDocs=len(trainMatrix)#统计矩阵行数,即文档数    numWords=len(trainMatrix[0])#统计列数,即每个文档的字数    pAbusive=sum(trainCategory)/float(numTrainDocs)#计算文档属性的概率(P1,另一个就是P0)    p0Num=zeros(numWords)#建立零向量,长度为文档字数    p1Num=zeros(numWords)    p0Denom=0.0    p1Denom=0.0#以上是对概率的初始化    for i in range(numTrainDocs):#循环每个文档        if trainCategory[i]==1:#如果这个文档的属性是1            p1Num+=trainMatrix[i]#把第i行数据(或者第i个文档)赋给p1Num            p1Denom+=sum(trainMatrix[i])#求该文档中1的和,赋给。。。        else:            p0Num+=trainMatrix[i]            p0Denom+=sum(trainMatrix[i])    p1Vect=p1Num/p1Denom    p0Vect=p0Num/p0Denom    return p0Vect,p1Vect,pAbusive

在命令行输入以下命令检验:

#建立自己的数据集和类别,不使用上面的。data=[['to','my','worthless'],['dog','take','ate'],['stop','to','him']]listclass=[1,1,0]mylist=createVocalList(data)#mylist就是待检验的文档mylistOut[17]: ['to', 'worthless', 'take', 'ate', 'my', 'him', 'dog', 'stop']trainmat=[]#生成一个文本矩阵,代表着这个待检验文本在每个样本下的存在与否for postindoc in data:    trainmat.append(setOfWord2Vec(mylist,postindoc))trainmatOut[21]: [[1, 1, 0, 0, 1, 0, 0, 0], [0, 0, 1, 1, 0, 0, 1, 0], [1, 0, 0, 0, 0, 1, 0, 1]]#计算各个概率p0V,p1V,pAb=trainNB0(trainmat,listclass)pAbOut[23]: 0.66666666666666663p0VOut[24]: array([ 0.33333333,  0.        ,  0.        ,  0.        ,  0.        ,        0.33333333,  0.        ,  0.33333333])p1VOut[25]: array([ 0.16666667,  0.16666667,  0.16666667,  0.16666667,  0.16666667,        0.        ,  0.16666667,  0.        ])

在trainNB0的循环中,循环参数是行数,也就是类别数,也就是3,而不是列数(8),这一点要注意。在上面自己的数据中,前两行类别都是1,那么经过i=0和i=1后,p1Num=(11111010)(两个向量相加),p1Denom=6(即3+3),经i=2后,p0Num=(10000101)(第三个向量),p0Denom=3。这样就可以计算概率了。
以上计算的是文本中每个词在各个类别下出现的概率。

测试算法,修改分类器

上面计算了各个词在每个类别下的概率,下面就要计算多个概率的乘积来获得文档属于某个类别的概率。那么如果一个词的概率为0,总结果就是0,这显然不行。所以进行简单处理,所有词的初始出现数为1,分母初始化2,修改上述程序。修改p0Num\p0Denom\p1Num\p1Denom的初值,以及最后的概率计算,改为对数运算。

def trainNB0(trainMatrix,trainCategory):    numTrainDocs=len(trainMatrix)#统计矩阵行数,即文档数    numWords=len(trainMatrix[0])#统计列数,即每个文档的字数    pAbusive=sum(trainCategory)/float(numTrainDocs)#计算文档属性的概率(P1,另一个就是P0)    p0Num=ones(numWords)#建立o向量,长度为文档字数    p1Num=ones(numWords)    p0Denom=2.0    p1Denom=2.0#以上是对概率的初始化    for i in range(numTrainDocs):#循环每个文档        if trainCategory[i]==1:#如果这个文档的属性是1            p1Num+=trainMatrix[i]#把第i行数据(或者第i个文档)赋给p1Num            p1Denom+=sum(trainMatrix[i])#求该文档中1的和,赋给。。。        else:            p0Num+=trainMatrix[i]            p0Denom+=sum(trainMatrix[i])    p1Vect=log(p1Num/p1Denom)    p0Vect=log(p0Num/p0Denom)    return p0Vect,p1Vect,pAbusive

下面构建完整的分类器。

#创建朴素贝叶斯分类函数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=createVocalList(listOPosts)    trainMat=[]    for postinDoc in listOPosts:        trainMat.append(setOfWord2Vec(myVocabList,postinDoc))    p0V,p1V,pAb=trainNB0(array(trainMat),array(listClasses))    testEntry=['love','my','dalmation']    thisDoc1=array(setOfWord2Vec(myVocabList,testEntry))    #上面这一句的意思是检查myVocabList中的文字是否出现在testEntry中    print(testEntry,'classified as: ',classifyNB(thisDoc1,p0V,p1V,pAb))    testEntry=['stupid','garbage']    thisDoc2=array(setOfWord2Vec(myVocabList,testEntry))    print(testEntry,'classified as: ',classifyNB(thisDoc2,p0V,p1V,pAb))    return thisDoc1,thisDoc2

最后的return thisDoc1,thisDoc2是自己加的,检查结果。后一个函数是封装了一些操作。命令窗口输入以下:

testingNB()['love', 'my', 'dalmation'] classified as:  0['stupid', 'garbage'] classified as:  1Out[31]: (array([0, 0, 0, ..., 1, 0, 0]), array([0, 0, 0, ..., 0, 1, 0]))

我们可以看到,thisDoc1结果是([0, 0, 0, …, 1, 0, 0]),中间有一些省略号,看不到中间是什么数据,这时我们可以在开头定义numpy的下面,输入一行’np.set_printoptions(threshold=np.inf)’,可以保证数据全部显示,另外我也将myVocabList输出(return稍作修改即可):

testingNB()['love', 'my', 'dalmation'] classified as:  0['stupid', 'garbage'] classified as:  1Out[42]: (array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,        0, 0, 0, 0, 0, 0, 1, 0, 0]), array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        0, 0, 1, 0, 0, 0, 0, 1, 0]),['to',  'worthless',  'ate',  'quit',  'stop',  'steak',  'take',  'has',  'I',  'problem',  'park',  'dog',  'so',  'love',  'is',  'posting',  'flea',  'not',  'help',  'maybe',  'my',  'licks',  'food',  'cute',  'buying',  'stupid',  'how',  'please',  'him',  'dalmation',  'garbage',  'mr'])

以上我们可以看到[‘love’, ‘my’, ‘dalmation’]的出现,用1表示,而之前我们得到了一个概率分布,这样thisDoc1(thisDoc2)表示待测文本在当前环境下的表示(仍保持thisDoc1的意义),这样再利用函数classifyNB就可以计算thisDoc1是否属于侮辱性文档的概率。

注:处理垃圾邮件尚未学习,等回顾上述思路待后续。

原创粉丝点击