您的位置:首页 > 其它

MLA Review之三:朴素贝叶斯分类

2016-02-28 22:50 246 查看
朴素贝叶斯(Naive Bayes),贝叶斯概率论在整个统计学习上都是泰山北斗一样的存在,《Pattern Recognization and Machine Learning》这一扛鼎之作全书的思想其实就是贝叶斯概率论,简单的说就是先验代替后验。

我们先来给朴素贝叶斯找一点理论支持

贝叶斯概率公式:P(A|B)=P(A)*p(B|A)/P(B) ,而根据要求,我们需要做的是得出P(C1|X,Y)和P(C2|X,Y)的概率,其中P(C1|X,Y)的意思是根据特征值X,Y得到是C1的概率,后面是得到C2的概率,因此,我们只需要比较这两者的大小就知道结果是归为哪一类了,但是问题是这个根本不好计算,这时候贝叶斯准则就可以派上用场了:

P(C1|X,Y)=P(C1)*P(X,Y|C1)/P(X,Y)

其中P(X,Y)是可以忽略的,因此P(C1|X,Y)约等于P(C1)*P(X,Y|C1),这个时候我们可以用经验概率来计算P(C1),但是计算P(X,Y|C1)仍然有难度,为了简单起见,朴素贝叶斯假设X,Y是独立的,所谓朴素也就指的是这个独立假设,也就是P(X,Y|C1)=P(X|C1)*P(Y|C1),这样就很容易计算该值了,可以得到:

P(C1|X,Y)=P(C1)*P(X|C1)*P(Y|C1),这样就容易计算了。

背景粗略交代完毕,现在回到具体问题:

邮件分类器:邮件分类垃圾邮件个正常邮件,根据已有的邮件训练样本,训练出邮件分类模型。

数据说明:25封垃圾邮件,25封正常邮件,在这50封邮件里面随机选取10篇作为测试数据,剩下40篇作为训练数据

算法说明

根据所给的训练邮件,得到所有的不重复单词数组,记为wordlist
将训练数据和测试数据按照wordlist的顺序转换成词向量
根据词向量使用NaiveBayes训练模型
使用测试数据集测试结果

下面是具体代码:

Python代码


# -*- coding: UTF8 -*-

"""

author:luchi

date:16/2/18

desc:

朴素贝叶斯做邮件分类

"""

"""

获取训练与测试文本,构建训练集与测试集

"""

import re

import random

from numpy import *

def splitWords(str):

listTokens=re.split(r'\W*',str)

return [token.lower() for token in listTokens if len(token)>2 ]

def initDataset():

wordList=[]

docList=[]

labels=[]

for i in range(1,26):

fr=open('email/spam/%d.txt' % i)

frStr=fr.read()

l=splitWords(frStr)

docList.append(l)

labels.append(0)

wordList.extend(l)

fr=open('email/ham/%d.txt' % i)

frStr=fr.read()

l=splitWords(frStr)

docList.append(l)

labels.append(1)

wordList.extend(l)

# print wordList

# print docList

#随机选出10个组作为测试

length=len(docList)

testList=[]

testLabels=[]

for i in range(10):

randIndex=int(random.uniform(0,len(docList)))

testList.append(docList[randIndex])

testLabels.append(labels[randIndex])

del(docList[randIndex])

del(labels[randIndex])

return wordList,docList,labels,testList,testLabels,length

"""

创建训练和测试向量

"""

def getVecDataset(wordList,trainList,testList):

wordList=set(wordList)

wordvec=[token for token in wordList]

feature_num=len(wordvec)

print len(wordvec)

trainVec=zeros((len(trainList),feature_num))

testVec=zeros((len(testList),feature_num))

for i,l in enumerate(trainList):

for word in l:

if word in wordvec:

trainVec[i][wordvec.index(word)]+=1

for i,l in enumerate(testList):

for word in l:

if word in wordvec:

testVec[i][wordvec.index(word)]+=1

return trainVec,testVec

def NaiveBayes(traingList,trainLabel):

trainMat=array(traingList)

labelMat=array(trainLabel)

class0=ones(len(trainMat[0]))

sumClass0=2.0

class1=ones(len(trainMat[0]))

sumClass1=2.0

m=len(trainMat)

pclass0=0

for i in range(m):

if(trainLabel[i]==0):

class0+=trainMat[i]

sumClass0+=sum(trainMat[i])

pclass0+=1

elif trainLabel[i]==1:

class1+=trainMat[i]

sumClass1+=sum(trainMat[i])

# print class0

# print sumClass0

class0=class0/sumClass0

class1=class1/sumClass1

class0=log(class0)

class1=log(class1)

return class0,class1,pclass0

def testNaiveBayes(testVec,vec0,vec1,pclass0):

p0=sum(testVec*vec0)+log(pclass0)

p1=sum(testVec*vec1)+log(1-pclass0)

if(p0>p1):

return 0

else:

return 1

def test():

wordList,trainList,trainLabels,testList,testLabels,doc_num=initDataset()

trainVec,testVec=getVecDataset(wordList,trainList,testList)

class0Vec,class1Vec,pclass0=NaiveBayes(trainVec,trainLabels)

m=len(testVec)

err=0

pclass0=float(pclass0)/len(trainVec)

for i in range(m):

vec=testVec[i]

label=testLabels[i]

result=testNaiveBayes(array(vec),class0Vec,class1Vec,pclass0)

if result!=label:

err+=1

print ("error rate is %f" % (float(err)/m))

if __name__=="__main__":

test()

注意程序中使用的log方法不是math包里的log方法,而是numpy里面的log方法,所以不要引入math包即可

测试的结果是:











可以看到,在5次测试中,只有一次的错误率为10%,其他全是0

朴素贝叶斯在使用起来容易,操作简单,却往往在一些问题上有着惊人的高效,这也是其强大的原因,但是朴素贝叶斯并不是对所有问题都适用,其独立假设就已经表示对一些对特征值有着明显先后或者依赖关系的时候,朴素贝叶斯的独立假设是不成立的,所以使用朴素贝叶斯还是实现需要看下具体的问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: