机器学习实战之朴素贝叶斯

作者: 罗罗攀 | 来源:发表于2018-06-10 16:46 被阅读220次

    在学习朴素贝叶斯分类模型之前,我们回顾一下之前学习的KNN和决策树,读者本人的总结:不同的机器学习方法有着不同的假设和理论进行支撑,而这些假设和理论在很大程度上体现了该算法的优缺点。
    KNN:在样本空间中,相同的类型数据在空间呈聚集状态,也就是距离会靠近,基于这个假设,只需要对测试样本与训练样本进行距离计算,最近距离的样本的类别很大程度上就是测试样本的类别。
    决策树:基于信息理论。样本数据是混乱的(熵高),但好在有特征这个东西,如何有效利用特征让样本不混乱,可分,这就是决策树需要完成的事情。
    而今天介绍的朴素贝叶斯是基于贝叶斯准则的算法,那为啥要加个朴素呢?因为臣妾做不到啊!(朴素贝叶斯假设特征独立且同等重要)。

    朴素贝叶斯原理

    如图,为我们的样本数据集。


    样本

    我们现在用 p1(x,y) 表示数据点 (x,y) 属于类别 1(图中用圆点表示的类别)的概率,用 p2(x,y) 表示数据点 (x,y) 属于类别 2(图中三角形表示的类别)的概率,那么对于一个新数据点 (x,y),可以用下面的规则来判断它的类别:

    • 如果 p1(x,y) > p2(x,y) ,那么类别为1
    • 如果 p2(x,y) > p1(x,y) ,那么类别为2

    也就是说,我们会选择高概率对应的类别。这就是该算法的核心思想,但如何计算p1(x,y) 和p2(x,y)呢?这里就需要条件概率和贝叶斯准则的知识了。

    条件概率和贝叶斯准则

    条件概率是在B发生的前提下,A发生的概率,数学公式为P(A|B)。我们来看下书中的案例:
    一个装了 7 块石头的罐子,其中 3 块是白色的,4 块是黑色的,那取出白色的概率为3/7,取出黑色的为4/7,这个很简单。


    案例

    如果用两个桶进行存放,如图所示,在B桶的情况下取出白球的概率是多少呢?很明显是1/3,图中是可以看出来的,但当问题复杂时,直接求就很困难,这里就需要条件概率公式:


    公式 案例

    另一种计算条件概率的算法为贝叶斯准则:


    公式
    算法原理

    我们继续看之前的案例:

    • 如果 p1(x,y) > p2(x,y) ,那么类别为1
    • 如果 p2(x,y) > p1(x,y) ,那么类别为2
      这里我们用条件概率的写法,p(c1|x,y)和p(c2|x,y),这个在实际中很不好求解,所以使用贝叶斯准则:
    公式

    这样就变为了:

    • 如果 P(c1|x, y) > P(c2|x, y), 那么属于类别 c1
    • 如果 P(c2|x, y) > P(c1|x, y), 那么属于类别 c2

    朴素贝叶斯之文本分类

    问题描述与数据

    以在线社区的留言板为例,有侮辱性的文字(1)和正常言论(0),该数据也是自己创建的。

    def loadDataSet():
        """
        创建数据集
        :return: 单词列表postingList, 所属类别classVec
        """
        postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], #[0,0,1,1,1......]
                       ['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 is abusive, 0 not
        return postingList, classVec
    
    构建词向量

    我们都知道计算机是不能直接识别文字的,这时就需要将文字转换为数字,怎么进行转换呢?
    例如这里有两段文字:

    • 我爱中国
    • 我不喜欢吃苹果

    首先对文本进行切分,然后组成没有重复的列表(词汇表):
    [我, 爱, 中国, 不喜欢, 吃苹果]
    然后针对词汇表,对两段文字进行向量化,出现的词就会赋值为1,否则为0,则两段文字转换为下面两个词向量。

    • [1, 1, 1, 0 ,0]
    • [1, 0, 0, 0 ,0]

    下面代码构建词向量:

    def createVocabList(dataSet):
        vocabSet= set([])
        for i in dataSet:
            vocabSet = vocabSet | set(i)
        return list(vocabSet)
    
    def set0fWords2Vec(vocabList, inputSet):
        returnVec = [0]*len(vocabList)
        for word in inputSet:
            if word in inputSet:
                returnVec[vocabList.index(word)] = 1
        return returnVec
    
    训练算法

    由于是多个特征,这里计算公式写为w矩阵形式:


    公式

    代码如下:

    from numpy import *
    def trainNB0(trainMatrix, trainCategory):
        numTrainDocs = len(trainMatrix)
        numWords = len(trainMatrix[0])
        pAbusive = sum(trainCategory)/float(numTrainDocs)
        p0Num = ones(numWords);p1Num = ones(numWords)
        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])
        p1Vect = log(p1Num/p1Denom)
        p0Vect = log(p0Num/p0Denom)
        return p0Vect, p1Vect, pAbusive
    
    测试算法

    最后对算法进行测试:

    def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
        p1 = sum(vec2Classify * p1Vec) + log(pClass1) # P(w|c1) * P(c1) ,即贝叶斯准则的分子
        p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) # P(w|c0) * P(c0) ,即贝叶斯准则的分子·
        if p1 > p0:
            return 1
        else:
            return 0
    
    def testingNB():
        listOPosts, listClasses = loadDataSet()
        myVocabList = createVocabList(listOPosts)
        trainMat = []
        for postinDoc in listOPosts:
            trainMat.append(set0fWords2Vec(myVocabList, postinDoc))
        p0V, p1V, pAb = trainNB0(array(trainMat), array(listClasses))
        testEntry = ['love', 'my', 'dalmation']
        thisDoc = array(set0fWords2Vec(myVocabList, testEntry))
        print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb))
        testEntry = ['stupid', 'garbage']
        thisDoc = array(set0fWords2Vec(myVocabList, testEntry))
        print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb))
    
    结果

    算法优缺点

    • 优点:数据量少也可以使用,可以处理多类问题
    • 缺点:对数据较敏感

    相关文章

      网友评论

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

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