美文网首页
机器学习实战三(朴素贝叶斯)

机器学习实战三(朴素贝叶斯)

作者: 人机分离机 | 来源:发表于2017-10-29 14:32 被阅读0次

    一、概述

    1. 原理:

    • 工作机制:

    2. 优缺点

    • 优点:在数据少的情况下有效,可以处理多类别问题
    • 缺点:
      • 对于输入数据的准备方式较为敏感
    • 适用数据范围:标称型数据

    3.条件概论:

    • 在B的条件下A出现的概率。
      p(A|B)=p(AB)/p(B)
    • 交换条件中的条件与结果:
      p(B|A)=p(A|B)*p(B)/p(A)

    4.贝叶斯决策理论的核心思想:

    • 选择具有最高概论的决策

    5.朴素贝叶斯算法的两个假设:

    • (1)每个特征之间都是独立的,这就使得公式:
    • p((f1,f2,...fn)|c)=p(f1|c)p(f2|c)...p(fn|c)
    • (2)每个特征同等重要,我们拿文本分类做例子,把文档中的单词作为特征。这种假设使得我们在进行分类的过程中无需考虑单词出现的次数,只考虑单词出现与否。这也就贝叶斯算法的贝努利模型实现方式。
    • 注:贝叶斯的另一种实现方式为多项式模型,在这种模型中则需要考虑单词的出现次数。

    二、算法流程

    1. 收集数据:可用任何方法
    2. 准备数据:需要数值型或者布尔型数据
    3. 分析数据:有大量特征时,绘制特征作用不大,此时使用直方图效果更好
    4. 训练算法:计算不同的独立特征的条件概率
    5. 测试算法:计算错误率
    6. 使用算法:一个常见的朴素贝叶斯应用是文档分类。可以在任意的分类场景中使用朴素贝叶斯分类器,不一定非要是文本。

    三、算法实践

    1.问题

    • 对是否属于侮辱性文章进行分类

    2.准备数据:从文本中构建词向量

    • 准备数据
    # 产生训练数据
    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']]
        # 标注每条数据的分类,这里0表示正常言论,1表示侮辱性留言
        classVec = [0, 1, 0, 1, 0, 1]
        return postingList, classVec
    
    # 建立词汇表
    def createVocabList(dataSet):
        # 首先建立一个空集
        vocabSet = set([])
        # 遍历数据集中的每条数据
        for document in dataSet:
            # 这条语句中首先统计了每条数据的词汇集,然后与总的词汇表求并集
            vocabSet = vocabSet | set(document)
        return list(vocabSet)
    
    # 按照词汇表解析输入
    def setOfWords2Vec(vocabList, inputSet):
        # 创建一个跟词汇表(vocabList)等长的向量,并将其元素都设为0
        returnVec = [0]*len(vocabList)
        # 遍历输入,将含有词汇表单词的文档向量设为1
        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
    
    命令行
    >>> import bayes
    >>> listOPosts,listClasses = bayes.loadDataSet()
    >>> myVocabList = bayes.createVocabList(listOPosts)
    >>> myVocabList
    >>> bayes.setOfWords2Vec(myVocabList,listOPosts[0])
    >>> bayes.setOfWords2Vec(myVocabList,listOPosts[3])
    

    3.训练算法:从词向量计算概率

    # 朴素贝叶斯分类器训练函数
    # 输入参数trainMatrix表示输入的文档矩阵,trainCategory表示每篇文档类别标签所构成的向量
    def trainNB0(trainMatrix,trainCategory):
        # 留言数目
        numTrainDocs=len(trainMatrix)
        # 变换矩阵的列数目,即词汇表数目
        numWords=len(trainMatrix[0])
        # 侮辱性留言的概率
        pAbusive=sum(trainCategory)/float(numTrainDocs)
        # 将所有词的出现数初始化为1,将分母初始化为2,从而降低计算多个概率的乘积结果为零的影响
        p0Num=ones(numWords)
        p1Num=ones(numWords)
        p0Denom=2.0
        p1Denom=2.0
        for i in range(numTrainDocs):
            # 统计每类单词的数目,注意我们这里讨论的是一个二分问题
            # 所以可以直接用一个if...else...即可,如果分类较多,则需要更改代码
            if trainCategory[i] == 1:
                p1Num += trainMatrix[i]
                p1Denom += sum(trainMatrix[i])
            else:
                p0Num += trainMatrix[i]
                p0Denom += sum(trainMatrix[i])
        # 对每个类别除以该类中的总词数
        # 防止下溢出
        p1Vec = log(p1Num/p1Denom)
        p0Vec = log(p0Num/p0Denom)
        # 函数返回两个概率向量,及一个概率
        return p0Vec, p1Vec, pAbusive
    
    >>> import bayes
    >>> listOPosts,listClasses = bayes.loadDataSet()
    # 该语句从预先加载值中调入数据
    >>> myVocabList = bayes.creatVocabList(listOPosts)
    >>> trainMat=[]
    >>> for postinDoc in listOPosts:
    ...   trainMat.append(bayes.setOfWords2Vec(myVocabList,postinDoc))
    ...
    # 下面给出属于侮辱性文章的概论以及两个类别的概论向量
    >>> p0V,p1V,pAb=bayes.trainNB0(trainMat,listClasses)
    >>> pAb
    >>> p0V
    >>> p1V
    

    4.测试算法: 朴素贝叶斯分类函数

    # 朴素贝叶斯分类函数
    def classifyNB(vec2Classify, p0Vec, p1Vec, pClass):
        p1 = sum(vec2Classify*p1Vec)+log(pClass)
        p0 = sum(vec2Classify*p0Vec)+log(1-pClass)
        if p1 > p0:
            return 1
        else:
            return 0
    
    • 该函数是用来测试(封装了一些操作)
    #内嵌测试函数
    def testingNB():
        listOPosts, listClasses=loadDataSet()
        myVocabList = createVocabList(listOPosts)
        trainMat = []
        for postinDoc in listOPosts:
          trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
        p0V, p1V, p1 = trainNB0(trainMat, listClasses)
        testEntry = ['love', 'my', 'dalmation']
        thisDoc = setOfWords2Vec(myVocabList, testEntry)
        print(testEntry, "classified as:", classifyNB(thisDoc, p0V, p1V, p1))
        testEntry = ['garbage', 'stupid']
        thisDoc = setOfWords2Vec(myVocabList, testEntry)
        print(testEntry, "classified as:", classifyNB(thisDoc, p0V, p1V, p1))
    
    命令行
    import bayes
    >>> bayes.testingNB()
    ['love', 'my', 'dalmation'] classified as: 0
    ['garbage', 'stupid'] classified as: 1
    
    

    5.词袋模型的转换函数(准备数据中优化)

    • 之前的算法我们只考虑了单词出现与否,使用的是一种词集模型。
    • 贝叶斯有两种实现方式,另一种多项式模型,需要考虑每个单词出现的次数,就是所谓的词袋模型。
    • 为了适应这种词袋模型,我们需要对函数setOfWords2Vec作一下修改
    #词袋模型的转换函数  
    def bagOfWords2VecMN(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  
    

    四、示例:使用朴素贝叶斯进行垃圾邮件过滤

    1.准备数据,切分文本

    # 该函数将每个句子都解析成单词,并忽略空格,标点符号以及长度小于3的单词
    def textParse(bigString):
        import re
        listOfTokens = re.split(r'\W*', bigString)
        return [tok.lower() for tok in listOfTokens if len(tok) > 2]
    

    2.分类器

    错误信息合集(参考)

    # 检测垃圾邮件
    def spamTest():
        # 存放输入数据
        docList = []
        #存放类别标签
        classList = []
        # 所有的文本
        fullText = []
        # 分别读取邮件内容
        for i in range(1, 26):
            wordList = textParse(open('email/spam/%d.txt' % i, "rb").read().decode('GBK','ignore') )
            docList.append(wordList)
            fullText.extend(wordList)
            classList.append(1)
            wordList = textParse(open('email/ham/%d.txt' % i,  "rb").read().decode('GBK','ignore') )
            docList.append(wordList)
            fullText.extend(wordList)
            classList.append(0)
        vocabList = createVocabList(docList)
        # range(50)表示从0到50,不包括50
        trainingSet = list(range(50))
        # 测试集
        testSet = []
        # 随机抽取是个作为测试集
        for i in range(10):
            # 从50个数据集中随机选取十个作为测试集,并把其从训练集中删除
            randIndex = int(random.uniform(0,len(trainingSet)))
            testSet.append(trainingSet[randIndex])
            del(trainingSet[randIndex])
        trainMat = []
        trainClasses = []
    
        for docIndex in trainingSet:
            trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))
            trainClasses.append(classList[docIndex])
        # 使用训练集得到概率向量
        p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))
    
        # 测试分类器的错误率
        errorCount = 0
        for docIndex in testSet:
            wordVector = setOfWords2Vec(vocabList, docList[docIndex])
            if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
                errorCount += 1
                print("Classification error:")
                print(docList[docIndex])
        print(errorCount)
        print("the error rate is:", float(errorCount)/len(testSet))
    

    github代码

    相关文章

      网友评论

          本文标题:机器学习实战三(朴素贝叶斯)

          本文链接:https://www.haomeiwen.com/subject/dwjypxtx.html