zoukankan      html  css  js  c++  java
  • 贝叶斯算法

    一、贝叶斯公式

    贝叶斯公式基于条件独立,通过条件概率公式全概率公式推导而来。

    1.条件独立

    条件独立的公式如下,其含义是当C发生时,A、B的发生互不干扰。
    P(A∩B|C)=P(A|C)∩P(B|C)<=>P(A|B,C)=P(A|C)<=>A,B对于C是条件独立的

    2.条件概率公式

    P(A|B)=P(AB)/P(B)
    变形公式:P(AB)=P(A|B)·P(B)=P(B|A)·P(A)

    3.全概率公式

    如果事件B1、B2、B3…Bn 构成一个完备事件组,即它们两两互不相容,其和为全集;并且P(Bi)大于0,则对任一事件A有
    P(A)=P(A|B1)P(B1) + P(A|B2)P(B2) + ... + P(A|Bn)P(Bn)。
    或者:p(A)=P(AB1)+P(AB2)+...+P(ABn)(其中A与Bn的关系为交)

    4.贝叶斯公式

    贝叶斯定义用来描述两个条件概率之间的关系,比如 P(A|B) 和 P(B|A)。下面是贝叶斯公式推导过程,其中①②③都是贝叶斯公式的变形。

    二、朴素贝叶斯分类

    1.概念

    贝叶斯分类是一类以贝叶斯定理为基础的分类算法的总称,朴素贝叶斯分类是其中之一,这里的“朴素”指各个特征之间是相互独立、互不影响的。主要应用于:求已知一些特征函数,求其属于某一类别的概率。
    P(类别|特征1,特征2,特征3...)=P(特征1,特征2,特征3...|类别)·P(类别)/P(特征1,特征2,特征3...)
    假设各个特征相互独立,则:
    P(类别|特征1,特征2,特征3...)=P(特征1,特征2,特征3...|类别)·P(类别)/[P(特征1)·P(特征2)·P(特征3)·...]

    2.实例

    我们想知道考试前一天逛街、刷视频、玩游戏、学习对成绩的影响。设:成绩优秀为1,成绩差为0;考试前一天逛街了为1,没有为0;考试前一天刷视频了为1,没有为0;考试前一天玩游戏了为1,没有为0;考试前一天学习了为1,没有为0。现有如下样本库:

    成绩 逛街 刷视频 玩游戏
    0 1 1 1
    0 1 0 1
    1 0 0 0
    0 0 0 0
    1 0 0 1
    0 0 1 1
    0 1 0 0
    1 1 0 1
    0 1 0 1
    0 1 0 1

    求考试前一天逛街了,玩游戏了,没有刷视频、学习,成绩优秀的概率是多少?
    P(1|1,0,1,0)
    =P(1,1,0,1,0)/[P(逛街=1)·P(刷视频=0)·P(玩游戏=1)·P(学习=0)]
    =0.1/(0.6 * 0.8 * 0.7 * 0.7)
    =0.4252

    我们再来算一下成绩差的概率为多少
    P(0|1,0,1,0)
    =P(0,1,0,1,0)/[P(逛街=1)·P(刷视频=0)·P(玩游戏=1)·P(学习=0)]
    =0.2/(0.6 * 0.8 * 0.7 * 0.7)
    =0.8503

    通过上面的计算,我们发现两个概率之和并不等于1。实际上在朴素贝叶斯分类器中,通过比较两个概率大小,判断属于哪个类别。由于分母时一样的,我们通常省去分母,只比较分子。

    三、拉普拉斯平滑

    拉普拉斯平滑主要处理零概率问题,就是在计算实例的概率时,如果某个量x,在观察样本库(训练集)中没有出现过,会导致整个实例的概率结果是0。在文本分类的问题中,当一个词语没有在训练样本中出现,该词语调概率为0,使用连乘计算文本出现概率时也为0。这是不合理的,不能因为一个事件没有观察到就武断的认为该事件的概率是0。

    为了解决零概率的问题,法国数学家拉普拉斯最早提出用加1的方法估计没有出现过的现象的概率,所以加法平滑也叫做拉普拉斯平滑。假定训练样本很大时,每个分量x的计数加1造成的估计概率变化可以忽略不计,但可以方便有效的避免零概率问题。

    四、项目实战

    1.

    (1)

    朴素贝叶斯根据先验概率(特征的可能性分布)有三种模型:高斯贝叶斯、伯努利贝叶斯、多项式贝叶斯。这三个类适用的分类场景各不相同,一般来说,如果样本特征的分布大部分是连续值,使用GaussianNB会比较好。如果样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适。而如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。

    sklearn 库中的 naive_bayes 模块实现了 5 种朴素贝叶斯算法:高斯贝叶斯、伯努利贝叶斯、多项式贝叶斯、分类贝叶斯、补充贝叶斯。

    后缀NB是朴素贝叶斯(Naive Bayes)的缩写

    Accuray表示测试集的准确率,cv=10表示十折交叉验证

    下面代码举了三种朴素贝叶斯分类,如果想看高斯朴素贝叶斯,把前三行代码高斯朴素贝叶斯取消注释,另两个注释,并将qnb=MultinomialNB()改为qnb=GaussianNB()。

    #from sklearn.naive_bayes import GaussianNB#高斯分布下的朴素贝叶斯分类
    #from sklearn.naive_bayes import BernoulliNB#驳伯努利分布
    from sklearn.naive_bayes import MultinomialNB#多项分布
    from sklearn.model_selection import cross_val_score
    from sklearn import datasets
    
    iris=datasets.load_iris()
    print(iris)
    qnb=MultinomialNB()
    scores=cross_val_score(qnb,iris.data,iris.target,cv=10,scoring='accuracy')
    print('Accuracy:%.3f'%scores.mean())
    

    若没有安装sklearn包,在终端输入pip install sklearn即可。

    cd C:UsersWAFFAppDataLocalProgramsPythonPython37Scripts
    
    pip install sklearn
    

    (2)k折交叉验证

    数据集包括训练集和测试集,我们一般用准确率Auc,即分类正确的样本个数占总样本的比例,来评价分类器的好坏。

    k折交叉验证,指将数据集分K个部分(K个格子):红色为测试集test,橙色为训练集train,每次划分都有一个准确率Auci,取其平均值为最终的准率率。

    2.垃圾邮件分类器

    垃圾邮件分类器,功能是将邮件样本集中垃圾邮件分类出来。以英文邮件为例,主要步骤为:

    (1)查看数据data:邮件内容

    (2)分词:句子->单词,以空格为标识

    (3)向量化:单词->数字->二进制

    (4)朴素贝叶斯公式:P(类别|单词1,单词2,单词3,...)=P(单词i|类别)*P(类别)/P(单词i)

    (5)结果

    代码中解释非常详细

    #朴素贝叶斯分类器训练函数
    #
    def trainNB0(trainMatrix,trainCategory):
        #总文件数
        numTrainDocs=len(trainMatrix)
        #总单词数
        numWords=len(trainMatrix[0])
        #侮辱性文件出现概率
        pAbusive=sum(trainCategory)/float(numTrainDocs)
        #构造单词出现次数列表
        #p0Num正确的统计
        #p1Num侮辱的统计
        p0Num=np.ones(numWords)
        p1Num=np.ones(numWords)
        #整个数据集单词出现的总数,根据样本/实际调查结果调整分母的值
        global p0Denom
        global p1Denom
        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])
        #类别1 即侮辱性文档的[log(F1/C1),log(F2/C2),log(F3/C3)...]避免0的产生,拉普拉斯平滑的一种方法取log?
        p1Vect=np.log(p1Num/p1Denom)
        #类别0 即正常文档的[log(F0/C0),log(F0/C0),log(F0/C0)...]
        p0Vect=np.log(p0Num/p0Denom)
        return p0Vect,p1Vect,pAbusive
    
    #切分文本
    def textParse(bigString):
        '''
        Desc:
            接收一个大字符串并将其解析为字符串列表
        Args:
            bigString--大字符串
            jieba 中文切分,自己查
        Returns:
            去掉少于2个字符的字符串,并将所有字符串转换为小写,返回字符串列表
        '''
        import re
        #使用正则表达式来切分句子,其中分隔符是除单词、数字外的任意字符串
        list0fTokens=re.split(r'w*',bigString)
        return [tok.lower() for tok in list0fTokens if len(tok)>2]
    
    def createVocabList1(dataSet):
        '''
        获取所有单词的集合
        :param dataSet:数据集
        :return:所有单词的集合(即不含重复元素的列表)
        '''
        vocabSet=set([])#creat empty set
        for document in dataSet:
            #操作符|用于求两个集合的并集
            vocabSet=vocabSet|set(document)#union of the two sets
        return list(vocabSet)
    
    def set0fWords2Vec(vocabList1,inputSet):
        '''
        遍历查看该单词是否出现,出现该单词则将该单词置1
        :param vocabList1:所有单词集合列表
        :return:匹配列表[0,1,0,1...],其中1与0表示词汇表中的单词是否出现在输入的数据集中
        '''
        #创建一个和词汇表等长的向量,并将其元素都设置为0
        returnVec=[0]*len(vocabList1)#[0,0,0...]
        #遍历文档中所有单词,如果出现了词汇表中的单词,则输出的文档向量中的对应值设为1
        for word in inputSet:
            if word in vocabList1:
                returnVec[vocabList1.index(word)]=1
            else:
                print ("the word :%s is not in my Vocabulary!" %word)
        return returnVec
    
    #朴素贝叶斯分类函数
    def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
        p1=sum(vec2Classify*p1Vec)+np.log(pClass1)
        p0=sum(vec2Classify*p0Vec)+np.log(1.0-pClass1)
        if p1>p0:
            return 1
        else :
            return 0
    
    def spamTest():
        '''
        Desc:对贝叶斯垃圾邮件分类器进行自动化处理
        Args:none
        Returns:
        '''
        docList1=[]
        classList1=[]
        fullText=[]
        for i in range(1,26):#前26个文件
            #切分,解析数据,并归类为1类别pythonLX
            wordList1=textParse(open('F:/Study/jupyterLX/pythonLX/0/%d.txt' % i,'r',encoding='ISO-8859-1').read())
            docList1.append(wordList1)
            fullText.extend(wordList1)
            classList1.append(1)
            #切分,解析数据,并归类为0类别
            wordList1=textParse(open('F:/Study/jupyterLX/pythonLX/1/%d.txt' % i,'r',encoding='ISO-8859-1').read())
            docList1.append(wordList1)
            fullText.extend(wordList1)
            classList1.append(0)
            #创建词汇表
            vocabList1=createVocabList1(docList1)
            trainingSet=list(range(50))
            testSet=[]
            #随机取10个邮件用来测试
            for i in range(10):
                #random.uniform(x,y)随机生成一个范围为x-y的实数
                randIndex=int(random.uniform(0,len(trainingSet)))
                testSet.append(trainingSet[randIndex])
                del(trainingSet[randIndex])
            trainMat=[]
            trainClasses=[]
            for docIndex in trainingSet:
                trainMat.append(set0fWords2Vec(vocabList1,docList1[docIndex]))
                trainClasses.append(classList1[docIndex])
                p0v,p1v,pSpam=trainNB0(np.array(trainMat),np.array(trainClasses))
                errorCount=0
            for docIndex in testSet:
                wordVector=set0fWords2Vec(vocabList1,docList1[docIndex])
                if classifyNB(np.array(wordVector),p0v,p1v,pSpam)!=classList1[docIndex]:
                    errorCount+=1
            print('the errorCount is :',errorCount)
            print('the testSet length is :',len(testSet))
            print('the error rate is :',float(errorCount)/len(testSet))
    
    import random
    import numpy as np
    import math
    spamTest()
    

    学习视频

  • 相关阅读:
    android 振动
    linux实用命令-查看文件夹的大小
    无显示屏的开发板抓屏
    传感器Sensor的使用-距离感应(听筒模式)
    4.4原生应用获取通话状态
    git服务器的使用
    (转)浅谈ANR及log分析ANR
    ubuntu下从软件中心安装软件时的软件缓存目录
    mysql————Innodb的可重复读的情况下如何避免幻读?
    MyISAM和Innodb的区别
  • 原文地址:https://www.cnblogs.com/Liang-Shan/p/14058866.html
Copyright © 2011-2022 走看看