朴素贝叶斯(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篇作为训练数据
? ? ? ?算法说明:
? ? ?下面是具体代码:
?
# -*- 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
?
朴素贝叶斯在使用起来容易,操作简单,却往往在一些问题上有着惊人的高效,这也是其强大的原因,但是朴素贝叶斯并不是对所有问题都适用,其独立假设就已经表示对一些对特征值有着明显先后或者依赖关系的时候,朴素贝叶斯的独立假设是不成立的,所以使用朴素贝叶斯还是实现需要看下具体的问题
?
代码和数据见下面
原文:http://luchi007.iteye.com/blog/2277288