分类问题之朴素贝叶斯模型
2016-03-09 23:00
716 查看
简介
朴素贝叶斯模型(Naive Bayes)是一种基于贝叶斯决策理论的分类方法。其核心思想就是选择具有最高概率的决策。如果用p1(x)表示特征向量x对应数据属于类别1的概率,用p2(x)表示特征向量x对应数据属于类别2的概率,那么可以利用下面的规则来判断它的类别:- 如果p1(x) > p2(x), 那么类别为1。
- 如果p2(x) > p1(x), 那么类别为2。
也就是说,我们更倾向于选择高概率对应的类别。
条件概率
条件概率:事件A在事件B已经发生的条件下发生的概率,记作p(A|B),读作”在B条件下A的概率”。计算方法:p(A|B) = p(AB)/p(B)
简单推导:由p(A|B) = p(AB)/p(B) [结论1],不难推出p(B|A) = p(AB)/p(A) [结论2],综合结论1和结论2,推出:p(A|B) = p(B|A)*p(A)/p(B)
p(A|B) = p(B|A)*p(A)/p(B)是一个非常神奇的公式,它表示除了”在B条件下A的概率”与”在A条件下B的概率”之间的关系,而朴素贝叶斯分类模型算法的核心就是基于这个关系。
分类模型
那么,如何利用训练样本集以及条件概率来构造朴素贝叶斯模型呢?机器学习的一个重要应用就是文档的自动分类。在文档分类中,整个文档(如一封电子邮件)是实例,而电子邮件中的某些元素则构成特征。如果你是一个QQ邮箱用户,当你打开你的QQ邮箱的垃圾箱的时候你会发现,垃圾箱里面有很多邮件并不是你手动删除的,而是被自动分类到了垃圾邮箱中。这就是一个简单、经典的文档分类问题的场景。
简单来讲,我们可以通过观察文档中出现的词,并把每个词出现或不出现(或者出现次数)作为一个特征,这样得到的特征数目就会跟词汇表中的词目一样多。朴素贝叶斯就是文档分类问题的常用算法。
朴素的含义:假设词汇表中共有1000个词,那么特征向量x就是1000维的。由统计学知,如果每个特征需要N个样本,那么对于10个特征将需要N^10个样本,对于包含1000个特征的词汇表将需要N^1000个样本,这种情况下我们是不可能完成模型构建的。但是,如果假设特征之间相互独立:即一个特征(单词)是否出现或者出现的可能性与它和其他单词没有任何约束关系。举个例子,假设单词bacon出现在unhealthy后面和出现在delicious后面的概率相同(当然我们知道这种假设并不正确,bacon经常出现在delicious附近,而很少出现在unhealthy附近)。这个假设正是朴素贝叶斯分类器中朴素(naive)一词的含义。
A bit consciously naive, don’t you think?
接下来,我们开始展开构造朴素贝叶斯模型。
符号定义:c表示分类,x表示特征。在二分类问题中ci(1<=i<=2)表示分类i。xi(1<=i<=n)表示特征i的值,其中n表示特征数,xi为1表示文档中出现了词汇表的第i个单词;反之,0表示文档中没有出现词汇表的第i个单词。
由前面基于条件概率公式推导出来的关系,可得:p(ci|x) = p(x|ci)*p(ci)/p(x)
其中:
- p(ci|x)表示特征向量是类别ci概率
- p(x|ci)表示训练样本中ci类别中出现特征向量x的概率,如果将x展开为一个个堵路的特征,那么就可以等价写作p(x0,x1,x2,…,xn|ci),这里假设所有次都独立,这就意味着可以使用p(x0|ci)*p(x1|ci)*p(x2|ci)*…*p(xn|ci)
- p(ci)表示训练样本中一个样例是cile类别的概率
- p(x)表示一个文档的特殊向量为x的概率
上述4个概率中,p(x)是不同类别公用的计算因子(分母),不影响计算结果因此不需要计算。其他3个,都可以通过对训练样本简单的统计计算得出。
那么,特征向量x所属为ck,满足:p(ck|x) = max{p(x|ci)*p(ci)}, 1<=i<=2
python代码实现
#!/usr/bin/python #encoding=utf-8 ''' @author: slowalker @date: 2015-06-07 ''' from numpy import * #构造训练数据集 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'], ['stop', 'buying', 'worthless', 'dog', 'food', 'stupid']] #每个文本数据对应的分类 classVec = [0, 1, 0, 1, 0, 1] return postingList, classVec #词集模型(set-of-words model):创建一个包含在所有文档中国年出现的不重复词的列表 def createVocabList(dataSet): vocabSet = set([]) for document in dataSet: vocabSet = vocabSet | set(d 4000 ocument) return list(vocabSet) #根基词汇表和输入文本,计算输入文本对应的文档向量 def setOfWords2Vec(vocabList, inputSet): returnVec = [0] * len(vocabList) #python中list的*运算表示将list中的元素重复复制若干次 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 #训练模型 def trainNB0(trainMatrix, trainCategory): numTrainDocs = len(trainMatrix) numWords = len(trainMatrix[0]) #计算分类为1的概率 pAbusive = sum(trainCategory) / float(numTrainDocs) #拉普拉斯平滑 p0Num = ones(numWords) p1Num = ones(numWords) p0Denom = 2.0 p1Denom = 2.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 = log(p1Num / p1Denom) p0Vect = log(p0Num / p0Denom) return p0Vect, p1Vect, pAbusive def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): #避免由于太多很小的数相乘造成乘法计算的下溢出,等价转化成对于的加法计算。 p1 = sum(vec2Classify * p1Vec) + log(pClass1) p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) if p1 > p0: return 1 else: return 0 if __name__ == '__main__': listOPosts, listClasses = loadDataSet() myVocabList = createVocabList(listOPosts) trainMat = [] for postInDoc in listOPosts: trainMat.append(setOfWords2Vec(myVocabList, postInDoc)) p0V, p1V, pAb = trainNB0(trainMat, listClasses) #查看模型训练的参数结果 #print pAb #后验概率 #print p0V #条件概率 #print p1V #条件概率 #构造数据集测试模型效果 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)
参考文档
《判别模型、生成模型与朴素贝叶斯方法》 by JerryLead《Machine Learning in Action》 by Peter Harrington
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- 用批处理解决数学问题的代码第1/4页
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例