基于概率论的分类方法:朴素贝叶斯

来源:互联网 发布:亿乐社区系统 v2.0源码 编辑:程序博客网 时间:2024/05/22 06:57

一 、什么是贝叶斯公式?

贝叶斯公式用来描述两个条件概率之间的关系:P(Y|X)=P(X|Y)P(Y)P(X)

以上公式也可变形为:P(Y,X)=P(Y|X)P(X)=P(X|Y)P(Y)

举例说明:

现分别有 A、B 两个容器,在容器 A 里分别有 7 个红球和 3 个白球,在容器 B 里有 1 个红球和 9 个白球,现已知从这两个容器里任意抽出了一个球,问这个球是红球且来自容器 A 的概率是多少?


假设已经抽出红球为事件 B,选中容器 A 为事件 A,则有:P(B) = 8/20,P(A) = 1/2,P(B|A) = 7/10,按照公式,则有:P(A|B) = (7/10)*(1/2) / (8/20) = 0.875

叶贝斯公司常用来计算已知先验概率求后验概率的情景。

二、什么是朴素叶贝斯公式?

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。即:加上条件独立假设的贝叶斯方法就是朴素贝叶斯方法(Naive Bayes)。

贝叶斯公式 + 条件独立假设 = 朴素贝叶斯方法

所谓的独立是统计意义上的独立,即每个条件发生的概率不受其它条件的影响。显然这是一种假设,但朴素贝叶斯的实际效果却很好。

三、使用朴素贝叶斯进行文档分类

(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代表有侮辱词汇,0没有    return postingList,classVec                 def createVocabList(dataSet):    vocabSet = set([])  #创建set空集合,用来存放无重复的样本数据    for document in dataSet:        vocabSet = vocabSet | set(document) #将每篇文章的新词汇添加到集合中    return list(vocabSet)def setOfWords2Vec(vocabList, inputSet):#判断词汇列表中的词汇是否在每组中,存在返回1,否则返回默认值0    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

三个函数的作用分别是:创建样本数据以及人工标注分类标签,1代表有侮辱词汇,0没有;创建无重复单词的词汇列表;把单词转换成向量。

(2)训练算法:从词向量计算概率

def trainNB0(trainMatrix,trainCategory):    numTrainDocs = len(trainMatrix)    numWords = len(trainMatrix[0])    pAbusive = sum(trainCategory)/float(numTrainDocs)#求有侮辱性的分类占总分类的比例    p0Num = zeros(numWords); p1Num = zeros(numWords)      #change to ones()     p0Denom = 0.0; p1Denom = 0.0                        #change to 2.0    for i in range(numTrainDocs):        if trainCategory[i] == 1:#计算侮辱词汇的数目,trainMatrix为0-1值形成的向量            p1Num += trainMatrix[i] # p1Num存储的是每个词在侮辱分类下出现的次数             p1Denom += sum(trainMatrix[i])# p1Denom存储的是侮辱分类下词的总数目          else:            p0Num += trainMatrix[i]            p0Denom += sum(trainMatrix[i])    p1Vect = p1Num/p1Denom         #计算侮辱词汇分类下每个词出现的概率    p0Vect = p0Num/p0Denom         #计算非侮辱词汇分类下每个词出现的概率    return p0Vect,p1Vect,pAbusive
该函数是用来计算每个词汇在1和0两大分类情况下的概率,返回的p0Vect,p1Vect结果如图所示:


但因为在计算多个概率的乘积时,其中有一个概率为0,那么最后的概率也为0,所以我们可以把所有词初始化为1,分母初始化为2.

p0Num = ones(numWords); p1Num = ones(numWords)      p0Denom = 2.0; p1Denom = 2.0 
此外,如果很多小概率数字相乘会出现下溢问题,所以我们对乘积取自然对数,

p1Vect = log(p1Num/p1Denom)        p0Vect = log(p0Num/p0Denom)  
进行如上操作后会得到与原始数据同等增加或减少的图像

(3)构造朴素贝叶斯分类函数:

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  def testingNB():  #挑选一些词汇,计算他属于两种分类的概率,并判断属于哪个分类 # 加载数据集      listOPosts,listClass = loadDataSet()      # 创建词汇列表      myVocabList = createVocabList(listOPosts)      trainMat = []      for postinDoc in listOPosts:          trainMat.append(setOfWords2Vec(myVocabList,postinDoc))      p0V,p1V,pAb = trainNB0(array(trainMat),array(listClass))      # print p0V,p1V,pAb      # print trainMat      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)  

两个函数分别构建了分类函数和测试函数,最后选择一些数据集进行测试,并返回概率大的标签。

、应用:用朴素贝叶斯过滤垃圾邮件

朴素贝叶斯最大的应用便是用来过滤垃圾邮件,我们选择25封垃圾邮件和25份非垃圾邮件使用算法根据以下步骤过滤垃圾邮件:

(1)收集数据:提供文本文件,下载地址:http://download.csdn.net/detail/liyuefeilong/9106481

(2)准备数据:将文本文件解析成词条向量;

(3)分析数据:检查词条确保解析的正确性;

(4)训练算法:使用我们之前建立的trainNB0()函数;

(5)测试算法:使用函数classifyNB(),并且构建一个新的测试函数来计算文档集的错误率;

 使用算法:构建一个完整的程序对一组文档进行分类,将错分的文档输出到屏幕上。

代码的Python语言实现如下:注意我们随机选择10个邮件作为测试集,用算法得到的分类标签与已知的分类标签比较,不相同则错误率加一。因为随机选择,所以每次运行的结果的不同,我们取十次的运行结果取平均值,得到错误率约为0.6.

def textParse(bigString):    #input is big string, #output is word list    import re    listOfTokens = re.split(r'\W*', bigString)    return [tok.lower() for tok in listOfTokens if len(tok) > 2]     def spamTest():    # 定义docList文档列表,classList类别列表,fullText所有文档词汇     docList=[]; classList = []; fullText =[]    for i in range(1,26):#导入并解析文件,spam为1,ham为0        wordList = textParse(open('email/spam/%d.txt' % i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(1)#根据文件名,判断文件分类        wordList = textParse(open('email/ham/%d.txt' % i).read())        docList.append(wordList)        fullText.extend(wordList)        classList.append(0)    vocabList = createVocabList(docList)#去除所以重复单词,创建词汇列表    trainingSet = range(50); testSet=[]#创建训练集,测试集    for i in range(10):#随机选取10份邮件为测试集,        randIndex = int(random.uniform(0,len(trainingSet)))        testSet.append(trainingSet[randIndex])# 将随机选择的文档加入到测试集中        del(trainingSet[randIndex])   # 从训练集中删除随机选择的文档    trainMat=[]; trainClasses = []    for docIndex in trainingSet:#train the classifier (get probs) trainNB0        trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))        trainClasses.append(classList[docIndex])    p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))    #print trainClasses  训练集邮件(40份)的分类结果,也就是正确的分类,classList根据文件名判断    errorCount = 0    for docIndex in testSet:        #从测试集中遍历邮件        wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])        print classifyNB(array(wordVector),p0V,p1V,pSpam)#调用classifyNB()分类函数,输出测试模型的分类结果        if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:#注意docIndex是取自测试集            errorCount += 1            print "classification error",docList[docIndex]    print 'the error rate is: ',float(errorCount)/len(testSet)

此外,要注意textParse()函数是对文本文件进行分词,单词长度小于2自动舍弃,最后的运行结果如图所示:

 


 


阅读全文
0 0