朴素贝叶斯
本章概念
- 概率分布
- 朴素贝叶斯分类器
前言
应利用分类器给出最优的判定结果,同时给出这个判定的概率估计值
概率分类器-假设
两个实例
- 词向量分类
- 垃圾邮件分类
1.基于贝叶斯决策理论的方法分类
贝叶斯决策理论,计算某数据从属于A类的概率与属于B类的概率,选择概率大的那个类别。
2.条件概率
p(c|x)
3.使用条件概率来分类
x应该是一个特征值组成的向量,利用贝叶斯公式算出
p(c|x)=p(x|c) p(c)/p(x)
c就是属于A或B甚至更多的选择,从中选定概率最大的,即p(c|x)最大的一个,作为该分类判定结果。
现在的问题就是到底如何计算等式右边的几个概率。
4.使用朴素贝叶斯进行文档分类
两个假设:
特征之前相互独立
每个特征同等重要-等权重
5.使用Python进行文档分类
5.1 准备数据
def loadDataSet():
postingList=[['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']]
classVec = [0,1,0,1,0,1] #1 is abusive, 0 not
return postingList,classVec
此函数为创建实验样本
def createvocablist(dataset):
vocbset = set([])
for document in dataset:
vocabset = vocabset | set(document)
return list(vocabset )
此函数是将数据集dataset中的每一个列表中元素合并 并 形成新的一个集合vocabset,也就是词汇表
|是求并集的符号
def setofwords2vec(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
此函数是判定输入的数据inputset中的元素是否在词汇表vocablist中,最终将出现在词汇表中的数据的位置输出成向量returnvec。
根据上述函数,即可完成,构造词汇表,寻找给定数据在词汇表位置的操作。
5.2 训练算法:从词向量计算概率
p(c|x)=p(x|c) * p(c) / p(x)
某类别的概率 p(c) ,计算比较简单,对应类数除以总数即可。
取到特征x全集(向量)的概率p(x),这一概率与分类无关,所以不需要考虑
对于条件概率p(x|c),即在某类下,取值为特征x全集(向量)的概率,如果考虑各特征相互独立,则该概率成为:对所有p(xi|c)求积。
trainmat=[]
for postindoc in listoposts:
trainmat.append(setofwords2vec(myvocablist,postindoc))
首先将每组单词数据转换成词汇表位置向量
应注意到词汇表的生成就是将训练集中的所有可能的单词数统一化形成的
还应注意,当转化成词汇表位置向量后,一个组内重复的单词已经被略去,后面会提到如果略去和不略去的区别-见5.4
def trainNB0(trainMatrix,traincategory):
numtraindocs = len(traincategory)
numwords = len(trainMatrix[0])
pabusive = sum(traincategory)/float(numtraindocs)
p0num = zeros(numwords)
p1num = zeros(numwords)
p1denom=0
p0denom=0
for i in range(numtraindocs):
if traincategory[i]==1:
p1num += trainMatrix[i]
p1denom += sum(trainMatrix[i])
else:
p0num += trainMatrix[i]
p0denom += sum(trainMatrix[i])
p1vect= p1num/p1denom
p0vect = p0num / p0denom
return p0vect,p1vect,pabusive
此函数先计算了判定为各类的概率
之后开始循环,每一次循环,考察当前当前单词组的判定类别
分别对应每个类别,将词汇表位置向量进行累加,最后的累加结果,即为词汇表中各单词出现次数
在每次循环中,还应该记录当前在字母表中的单词个数,同时分类累加,作为最终各类中单词出现的总数
最后用各类别下,各单词出现的次数除以总次数即为各单词出现的概率
输出的p1vect即为词汇表中各位置对应单词被归到1类的概率值
同理可得p0vect
5.3 测试算法:根据现实情况修改分类器
1.考虑到概率如果一个值为0,则与之相乘后的值全为零,将所有单词的出现数初始化为1,出现总数初始化为2。(2怎么来的不知道)
2.为保证最终概率积不能太小,从而被忽略成0,把概率取对数。
最终要比较 log( p(x|c) * p(c) )的值
def classifyNB(vec2classify,p0vec,p1vec,pclass1):
p1 = sum(vec2classify * p1vec) + log(pclass1)
p0 = sum(vec2classify * p2vec) + log(1.0 - pclass1)
if p1> p0:
return 1
else:
return 0
输入待分类的词汇位置向量vec2classify
用该向量各元素去乘对应各类概率向量在求和即得到:各单词在对应类条件下出现的概率积,只不过是对数值,所以求和。
同理后面加上类概率也是由于对数,实际上为乘积。
def testingNB():
listoposts,listclasses = loadDataSet()
myvocablist = createvocablist(listoposts)
trainmat=[]
for postindoc in listoposts:
trainmat.append(setofwords2vec(myvocablist,postindoc))
p0v,p1v,pab=trainNB0(trainmat,listclasses)
testentry=['love','my','dalmation']
thisdoc=array(setofwords2vec(myvocablist,testentry))
print(testentry,'classified as :',classifyNB(thisdoc,p0v,p1v,pab))
testentry = ['stupid', 'garbage']
thisdoc = array(setofwords2vec(myvocablist, testentry))
print(testentry, 'classified as :', classifyNB(thisdoc, p0v, p1v, pab))
return
这个函数就是运用前面几个函数,将测试集输入,最终输出判断类别。
5.4 准备数据:文档词袋模型
词袋模型即考虑每个训练集中的词如果出现多次,则进行累加,只需将setofwords2vec进行修改,
在记录对应位置出现的时候成为累加的方式。
def bagofwordsvec(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