基于概率论的分类方法:朴素贝叶斯

需要分类器做出分类决策,可以使分类器给出各个类别的概率估计值,然后选择概率最高的作为其的类别。在这里使用到了概率论中的贝叶斯公式:P(A|B)=P(A)*P(B|A)/P(B),其中P(A|B)是后验概率,P(A)是先验概率,P(B|A)/P(B)为调整因子(在已知结果的情况下对先验概率大小做出相应调整得到后验概率)

使用朴素贝叶斯进行文档分类

可以观察文档中出现的单词,并把每个词的出现或者不出现作为一个特征,这样的得到的特征数目就是单词表的词目数。

那么由统计学得知,如果每个特征需要N个样本,则一千个特征的词汇表需要N^1000个样本,但是如果假设特征之间是相互独立的,那么样本数就可以减少到1000*N(特征相互独立即特征之间完全没有关联和规律,互不影响,那么对其来说样本N^1000或是1000*N的意义是一样的),这也就是“朴素”的含义。当然这种假设并不正确,因为绝大多数特征之间并不可能是毫无关联毫无规律的,尽管如此,但朴素贝叶斯的实际效果却很好。

朴素贝叶斯的分类器通常有两种实现方式:一种是基于伯努力模型实现,一种是基于多项式模型实现。在文档分类中我们选择第一种模型,不考虑词在文档中出现多少次,只考虑出不出现(记录为0或1),因此在这个意义上我们假设的是所有词都是等权重的。

 

首先准备数据:需要我们把文本转换为相应的词条向量才能进行后面的运算。

import numpy as np
from functools import reduce 

def loadDataSet():
    datalist=[['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']]
    label = [0,1,0,1,0,1]           #各个词条的类别标签向量,1代表属于侮辱性词汇,0代表不是
    return datalist,label

def creatVocablist(dataset):        #创建一个词汇表,记录所有出现过的单词
    vocabuset=set([])
    for i in dataset:
        vocabuset=vocabuset|set(i)  #set(i)将该行中重复单词去除,并运算符将其并在词汇列表中
    return list(vocabuset)

def setwords_tovec(vocabulist,inputset): #根据词汇表,将inputset向量化,word存在则1,否则为零
    vec=[0]*len(vocabulist)              #初始化一个词汇表长度的列表
    for word in inputset:       
        if word in vocabulist:
            vec[vocabulist.index(word)]=1
        else:print("%s is not in my vocabulary!"% word)
    return vec

datalist,label=loadDataSet()
vocabulist=creatVocablist(datalist)                   #得到词汇表
trainmat=[]
for line in datalist:
    trainmat.append(setwords_tovec(vocabulist,line))  #得到向量化后的训练集
print("总词汇表为:\n" ,vocabulist)
print("向量化的训练集为:\n" ,trainmat)

 

 

 

 

下一步要开始训练算法,从词向量来计算概率。
我们的目标是已知一个词条的各个特征(有哪些单词出现了),然后给这个词条分类(是否属于侮辱性词条),X表示这是一个向量,它由多个数值组成,A代表属于侮辱类,B代表属于非侮辱类,那么根据贝叶斯公式:

文档属于侮辱类概率:P(A|W)=P(A)*P(W|A)/P(W)

文档不属于侮辱类概率:P(B|W)=P(B)*P(W|B)/P(W)

只需要比较两者大小即可,概率大的就是该文档的类别。其中P(W)可以用全概率公式求解,但此处并不用,因为比较大小P(W)可以同时约去,减少计算量。

那么P(A)就是所说的先验概率:P(A)=训练集文档中侮辱类数目÷训练集文档总数目

由特征独立分布可得:P(W|A)=P(w1|A)*P(w2|A)*......*P(wn|A),P(wn|A)则很好求,就是分类为A的词条中该单词出现的次数÷A分类所有单词出现次数的总数。

求出P(A)、P(W|A)就可以得到P(A|W),同理得到P(B|W),比较两者大小,选择概率大的作为它的分类结果。

#朴素贝叶斯分类器训练函数,求解需要的参数P(W|A),P(W|B),P(A),1-P(A)
def trainNB(trainmat,trainlabel):
    numdocs=len(trainmat)
    numwords=len(trainmat[0])
    Pabusive=sum(trainlabel)/float(numdocs)  #文档属于侮辱类的概率,即先验概率P(A)
    p0num=np.ones(numwords);p1num=np.ones(numwords) #初始化为一,加一平滑,解决零概率问题,避免出现某一特征概率为零从而导致P(X|A)为零
    p0denom=2.0;p1denom=2.0                         #分母初始化为二,原理相同
    for i in range(numdocs):
        if(trainlabel[i]==1):
            p1num+=trainmat[i]         #计算属于侮辱类的概率
            p1denom+=sum(trainmat[i])
        else:
            p0num+=trainmat[i]
            p0denom+=sum(trainmat[i])
    p1vec=np.log(p1num/p1denom)
    p0vec=np.log(p0num/p0denom)        #对特征概率P(Xn|A)做对数处理,避免下溢出(因为数值太小不断相乘越来越小导致最后四舍五入为零),采用对数处理不会造成任何损失。
    return p0vec,p1vec,Pabusive    

#根据得到的参数 p0vec,p1vec,Pabusive来计算最后的P1,P0并比较大小
def NBclassify(vec,p0vec,p1vec,Pabusive):  
    #reduce函数会对参数序列按照指定函数方法进行运算,使用lambda匿名函数
    #p1=reduce(lambda x,y:x*y,vec*p0vec)*Pabusive  根据公式本该如此计算,但是在取了对数之后可以利用对数的性质将乘法运算化为求和(log(ab)=log(a)+log(b))
    #p0=reduce(lambda x,y:x*y,vec*p1vec)*(1-Pabusive)  
    #改进后为:
    p1=sum(vec*p1vec)+np.log(Pabusive)     #并且取对数将连乘运算通过对数转换为求和,还避免了零概率问题!因为只要有一个为零则相乘结果就会变为零!
    p0=sum(vec*p0vec)+np.log(1-Pabusive)
    print('p0:',p0)
    print('p1:',p1)
    if p1 > p0:        #比较两者的概率选取最大的哪一个
        return 1
    else: 
        return 0

 

最后输入测试集,通过得到的分类器对其进行测试。

testEntry = ['love', 'stupid', 'dalmation']     #测试词条样本
thisDoc = np.array(setwords_tovec(vocabulist, testEntry))   #将测试样本向量化
p0vec,p1vec,Pabusive=trainNB(trainmat,label)                #放入训练器求解参数
print(p0vec,p1vec)
if NBclassify(thisDoc,p0vec,p1vec,Pabusive):
    print(testEntry,'属于侮辱类')                            #执行分类并打印分类结果
else:
    print(testEntry,'属于非侮辱类')   

结果显示为:

参考学习自《机器学习实战》 

推荐博客:http://blog.youkuaiyun.com/c406495762

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值