基于概率的分类方法:朴素贝叶斯
贝叶斯决策理论
朴素贝叶斯是贝叶斯决策理论的一部分,所以在讲解朴素贝叶斯之前我们先快速简单了解一下贝叶斯决策理论知识。
贝叶斯决策理论的核心思想:选择具有最高概率的决策。比如我们毕业选择就业方向,选择C++方向的概率为0.3,选择Java的概率为0.2,选择机器学习的概率为0.5。那么我们就把这样的一位毕业生就业方向归类为机器学习方向。
条件概率
什么是条件概率?事件A在另一个事件B已知发生条件下的发生概率,记为P(A|B),读作“在B条件下A的概率”。
例子1:有两个骰子,一个骰子扔出点数是6,那么扔另一个骰子时,求出两个骰子点数之和大于等于10的概率。
例子2:有三个箱子编号为1,2,3。1号箱子有1个红球4个白球,2号箱子有2个红球3个白球,3号箱子有3个红球。从三个箱子中任取一箱,从中任意摸出一个球,求取得红球的概率。
另一种有效计算条件概率的方法就是贝叶斯准则。贝叶斯准则告诉我们如何交换条件概率中的条件和结果,即如果已知P(x|c),要求P(c|x) , 此时我们可以使用这样的计算方法:P(c|x)*P(x)=P(x|c)*P(c)。
到目前为止,我们基本了解了贝叶斯决策理论和条件概率,我们就开始学习编写代码,用Python语言来试着实现朴素贝叶斯分类器吧。
朴素贝叶斯分类器
以留言板为例,为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的词语,就将这条留言标识为内容不当。过滤这类内容是很多网站的基本需求。这里,我们就将言论归为侮辱类和非侮辱类,分别用1和0来表示。
1 # coding : utf-8 2 from numpy import * 3 4 def loadDataSet(): 5 postingList = [['my', 'dog', 'has', 'flea', \ 6 'problems', 'help', 'please'], 7 ['maybe', 'not', 'take', 'him', \ 8 'to', 'dog', 'park', 'stupid'], 9 ['my' ,'dalmation', 'is', 'so', 'cute', \10 'I', 'love', 'him'],11 ['stop', 'posting', 'stupid', 'worthless', 'garbage'],12 ['mr', 'licks', 'ate', 'my', 'steak', 'how' \13 'to', 'stop', 'him'],14 ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']15 ]16 classVec = [0,1,0,1,0,1]17 return postingList, classVec18 19 def createVocabList(dataSet):20 vocabSet = set([])21 for doc in dataSet:22 vocabSet = vocabSet | set(doc)23 return list(vocabSet)24 25 def setOfWord2Vec(vocabList, inputSet):26 returnVec = [0]*len(vocabList)27 for word in inputSet:28 if word in vocabList:29 returnVec[vocabList.index(word)] = 130 else:31 print "the word: %s is not in my Vocabulary!" % word32 return returnVec 33
第一个函数loadDataSet()创建了一些实验样本。该函数返回的第一个变量是进行词条切分后的文档集合,这些文档来自对狗狗的留言板。第二个变量是一个类别标签的集合。这里有两类,分别是侮辱性和非侮辱性。
下一个函数createVocabList()会创建一个包含在所有文档中出现的不重复词的列表,使用了set数据类型。操作符“|”用于求两个集合的并集。
第三个函数的输入参数为词汇列表和某个文档,输出的是文档向量,向量的每一个元素为1或者0,分别表示词汇表中的单词在输入文档中是否出现过。
接下来我们看看执行这个函数块的效果是怎么样的。
1 # coding : utf-82 import bayes3 from numpy import *4 5 list2Posts, listClasses = bayes.loadDataSet()6 myVocabList = bayes.createVocabList(list2Posts)7 print myVocabList, len(myVocabList)8 print bayes.setOfWord2Vec(myVocabList, list2Posts[0])9 print bayes.setOfWord2Vec(myVocabList, list2Posts[3])
计算概率
1 def trainNBO(trainMatrix, trainCategory): 2 numTrainDocs = len(trainMatrix) 3 numWords = len(trainMatrix[0]) 4 pAbusive = sum(trainCategory)/float(numTrainDocs) 5 p0Num = zeros(numWords); p1Num = zeros(numWords) 6 p0Denom = p1Denom = 0.0 7 for i in range(numTrainDocs): 8 if trainCategory[i] == 1: 9 p1Num += trainMatrix[i]10 p1Denom += sum(trainMatrix[i])11 else :12 p0Num += trainMatrix[i]13 p0Denom += sum(trainMatrix[i])14 p1Vect = p1Num/p1Denom15 p0Vect = p0Num/p0Denom16 return p0Vect,p1Vect,pAbusive
万事俱备,只欠东风。接下来,就是重要的朴素贝叶斯分类函数了。
1 def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): 2 p1 = sum(vec2Classify * p1Vec) + log(pClass1) 3 p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) 4 if p1 > p0: 5 return 1 6 else : 7 return 0 8 9 def testingNB():10 listOPosts,listClasses = loadDataSet()11 myVocabList = createVocabList(listOPosts)12 trainMat = []13 for postinDoc in listOPosts:14 trainMat.append(setOfWord2Vec(myVocabList,postinDoc))15 p0V,p1V,pAb = trainNBO(array(trainMat),array(listClasses))16 testEntry = ['love', 'my', 'dalmation']17 thisDoc = array(setOfWord2Vec(myVocabList, testEntry))18 print testEntry, 'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)19 testEntry = ['stupid', 'garbage']20 thisDoc = array(setOfWord2Vec(myVocabList, testEntry))21 print testEntry, 'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
试试看我们的运算结果:
和我们期望的结果一样,文档单词正确的进行了分类。
总结:
朴素贝叶斯算法总体来说,是比决策树和KNN算法较复杂一些,代码量也相对而言多一些。回想起大一时期青涩的我,没有好好学习概率论,当时没有对其引起重视,导致如今这个鸟样。哎,只怪当时还年轻啊!条件概率部分有很多较复杂的概率公式还是很模糊,接下来会花一点时间在概率这方面。只要概率方面没问题的话,相信读懂以上这几份代码应该不成问题,classifyNB函数里就是在计算最终的概率。
加油吧,BaiYiShaoNian!