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
朴素贝叶斯在使用起来容易,操作简单,却往往在一些问题上有着惊人的高效,这也是其强大的原因,但是朴素贝叶斯并不是对所有问题都适用,其独立假设就已经表示对一些对特征值有着明显先后或者依赖关系的时候,朴素贝叶斯的独立假设是不成立的,所以使用朴素贝叶斯还是实现需要看下具体的问题
我们先来给朴素贝叶斯找一点理论支持
贝叶斯概率公式: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
朴素贝叶斯在使用起来容易,操作简单,却往往在一些问题上有着惊人的高效,这也是其强大的原因,但是朴素贝叶斯并不是对所有问题都适用,其独立假设就已经表示对一些对特征值有着明显先后或者依赖关系的时候,朴素贝叶斯的独立假设是不成立的,所以使用朴素贝叶斯还是实现需要看下具体的问题
相关文章推荐
- 端口占用处理(Windows)
- 分组密码的模式
- java学习(一)——环境的搭建与“Hellow World!”
- storage disk
- 排序算法6之堆排序
- 编程语言的语法和语义
- html - get the id of onclick(this), onfocus(this) or whatever(this)
- USACO Palindromic Squares 解题日志
- 写在前面
- Java反射机制的几点用法
- uva10020 - Minimal coverage(区间覆盖)
- 数据库逆向框架代码生成工具:MyBatis Generator的使用
- Linux内核及分析 第一周 计算机是如何工作的?
- Linux下搭建coreseek(sphinx+mmseg3)全文检索
- 21. Merge Two Sorted Lists
- UIView属性clipsTobounds的应用
- OA学习笔记-008-岗位管理Action层实现
- 使用JS实现RTMP协议直播(三)
- Toolbar使用方法
- HOJ-2056 Bookshelf(线性动态规划)