zoukankan      html  css  js  c++  java
  • 朴素贝叶斯(naive bayes)

    朴素贝叶斯(naive bayes)

    标签: Python 机器学习

    主要參考资料:《机器学习实战》《统计学习方法》


    1.朴素贝叶斯分类原理

    朴素贝叶斯法是基于贝叶斯定理特征条件独立假设(称为朴素的原因)的分类方法。先看看维基百科中贝叶斯定理的描写叙述:

    贝叶斯定理(维基百科)
    通常,事件A在事件B(发生)的条件下的概率。与事件B在事件A的条件下的概率是不一样的。然而,这两者是有确定的关系,贝叶斯定理就是这样的关系的陈述。


    公式描写叙述例如以下:

    P(A|B)=P(B|A)P(A)P(B)

    当中P(A|B)是在B发生的情况下A发生的可能性。

    在机器学习中,经常常使用事件A表示属于某个类别,事件B表示特征条件的集合。下面图作为样例解说:

    图中共同拥有两类点。记为c1c2p(ci|x,y)表示点(x,y)为类ci的概率。那么依据贝叶斯公式,能够进行例如以下分类:

    • 假设P(c1|x,y)>P(c2|x,y)。则断定该点属于c1
    • 假设P(c1|x,y)<P(c2|x,y)。则断定该点属于c2

    假设用P(x,y|ci)表示类ci中点(x,y)的概率(分布)。则:

    P(ci|x,y)=P(x,y|ci)P(ci)P(x,y)

    又由于假设了特征条件独立。即xy之间没有不论什么的关系。则:
    P(ci|x,y)=P(x|ci)P(y|ci)P(ci)P(x,y)

    分母同样,仅仅须要比較分子就可以。朴素贝叶斯算法训练的目的就是得到训练集中P(x|ci)P(y|ci)P(ci),即不同独立特征的条件概率

    2.朴素贝叶斯实现

    2.1准备数据

    由于是简单的演示样例,直接创建训练集和类标签向量:

    # 训练集:留言板的中的留言
    def create_data_set(): 
        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 create_vocablist(dataSet): 
        vocabSet = set([])  #create empty set
        for document in dataSet:
            vocabSet = vocabSet | set(document) #取并集
        return list(vocabSet)

    有了单词表就能够将语句转化为频率矢量,首先将单词表全部单词的频率初始化为0。然后遍历每一条语句。将出现的单词频率置为1(0表示未出现该单词,1表示出现该单词):

    #将输入语句转化为单词频率向量,表示单词表中的哪些单词出现过
    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

    利用上面生成的数据集生成一个单词表,结果例如以下:

    将语句”I buying cute dog”转化为向量例如以下:

    2.2训练算法

    先看看训练的目标參数:P(w1|ci),P(w2|ci),...,P(wm|ci)P(ci),当中wi表示某一个单词,由于一条语句是由若干单词组成。且我们假设每一个单词出现的事件是独立的。故类ci有语句w的概率P(w⃗ |ci)=P(w1|ci),P(w2|ci),...,P(wm|ci)

    训练函数传入的參数有两个。各自是语句集合转化的单词表向量集合和类标签向量。首先依据类标签列表能够计算出侮辱性语句和非侮辱性语句的频率。然后再计算各个特征的条件概率。

    计算特征的条件概率时使用了numpy中的矢量运算。极大的简化了程序的编写。先定义2个空的单词表矢量,用来统计侮辱性单词和非侮辱性单词的频数,再定义2个浮点型变量。用来统计侮辱性单词和非侮辱性单词的总数。遍历单词表向量集合。依据每一个向量的类别,统计侮辱性和非侮辱性单词的频数与总数。最后,将频数除以总数,就能够得到侮辱性或非侮辱性条件下某单词的出现的概率。

    #朴素贝叶斯训练函数,输入为全部文档的单词频率向量集合。类标签向量
    def trainNB(trainMatrix,trainCategory):
        numTrainDocs = len(trainMatrix) #文档数量
        numWords = len(trainMatrix[0]) #单词表长度
        pAbusive = sum(trainCategory)/float(numTrainDocs) #侮辱性词语的频率
        p0Num = zeros(numWords); p1Num = zeros(numWords) #分子初始化为0
        p0Denom = 0.0; p1Denom = 0.0                   #分母初始化为0
        for i in range(numTrainDocs):
            if trainCategory[i] == 1: #假设是侮辱性语句
                p1Num += trainMatrix[i] #矢量相加,将侮辱性语句中出现的词语频率全部加1
                p1Denom += sum(trainMatrix[i]) #屈辱性词语的总量也添加
            else:
                p0Num += trainMatrix[i]
                p0Denom += sum(trainMatrix[i])
        p1Vect = p1Num/p1Denom #对每一个元素做除法
        p0Vect = p0Num/p0Denom
        return p0Vect,p1Vect,pAbusive #返回全部词语非侮辱性词语中的频率。全部词语在侮辱性词语中的频率。侮辱性语句的频率

    可是这段程序有两个问题,问题一为可能发生下溢出,问题二为某语句的某个单词在侮辱性或非侮辱性集合中的频率为0,这会导致连乘的积为0.

    首先解决这个问题一:
    频率都是非常小的小数,这些小数连乘的结果终于也是非常小非常小的小数,在计算机中会发生下溢出或者为0,总之都不是正确的结果。

    较为常见的解决方法是使用对数。将连乘变为连加。对应的程序改动例如以下:

    p1Vect = log(p1Num/p1Denom) #变为对数,防止下溢出;对每一个元素做除法
    p0Vect = log(p0Num/p0Denom)

    然后解决这个问题二:
    能够通过分子全部初始化为1,分母初始化为2解决该问题,这样的方法在统计学中叫做贝叶斯预计
    条件概率P(wj|ci)的极大似然预计为:

    P(wj|ci)=I(wj,ci)I(ci)

    我们原先就是依照上面的公式计算P(wj|ci),可是该公式可能出现所要预计的概率值为0的情况,所以给分子分母添加一项,称为条件概率的贝叶斯预计,详细例如以下:
    P(wj|ci)=I(wj,ci)+λI(ci)+Sjλ

    当中λ>0Sj表示wj能够取得不同值的个数。当λ=1时,称为拉普拉斯平滑

    在我们所讨论的问题中。wj表示某个单词是否出现,仅仅有0和1两个值。故Sj=2。所以初始化时分子为1。分母为2,再依据遍历结果添加分子和分母的值。对应的程序改动例如以下:

    p0Num = ones(numWords); p1Num = ones(numWords) #分子初始化为1
    p0Denom = 2.0; p1Denom = 2.0                   #分母初始化为2

    2.3測试算法

    依据下面准则编写分类函数:

    • 假设P(c0|x,y)>P(c1|x,y),则断定为非侮辱性语句
    • 假设P(c0|x,y)<P(c1|x,y),则断定为侮辱性语句
    def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
        p1 = sum(vec2Classify * p1Vec) + log(pClass1) #矢量相乘求出概率。log相加
        p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
        if p1 > p0:
            return 1
        else: 
            return 0

    然后编写測试函数,进行測试,须要注意的是python中的列表不提供矢量运算,要想进行矢量运算,就要将列表转化为numpy中的array或者mat

    def testingNB():
        listOPosts,listClasses = create_data_set()
        myVocabList = create_vocablist(listOPosts)
        trainMat=[]
        for postinDoc in listOPosts:
            trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
        p0V,p1V,pAb = trainNB(array(trainMat),array(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)

    执行结果例如以下:

    3.总结

    • 源代码在我的GitHub中,MachineLearningAction仓库里面有常见的机器学习算法处理常见数据集的各种实例,欢迎訪问
    • 朴素贝叶斯算法核心就两个:
      • 贝叶斯定理
      • 朴素:假设各个特征之间是独立的
    • 仅仅要牢记朴素贝叶斯的核心以及公式,那么编敲代码就比較easy
    • 朴素贝叶斯经常常使用于文本分类。然而该方法对于英文等语言非常好用。对中文就不是非常好,由于中文是字组成词。对于长句子要进行“分词”操作,比方“黄金”和“金黄”的字全然一样,可是意思截然不同
    • 朴素贝叶斯有非常多的改进方法,比方说用词袋模型取代词集模型,移除停用词
  • 相关阅读:
    Proj THUDBFuzz Paper Reading: The Art, Science, and Engineering of Fuzzing: A Survey
    Proj THUDBFuzz Paper Reading: A systematic review of fuzzing based on machine learning techniques
    9.3 付费代理的使用
    11.1 Charles 的使用
    第十一章 APP 的爬取
    10.2 Cookies 池的搭建
    10.1 模拟登录并爬取 GitHub
    11.5 Appium 爬取微信朋友圈
    11.4 Appium 的基本使用
    11.3 mitmdump 爬取 “得到” App 电子书信息
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8615310.html
Copyright © 2011-2022 走看看