朴素贝叶斯算法

朴素贝叶斯算法

  • 简介:朴素贝叶斯算法是一种基于概率统计的分类方法。在条件独立假设的基础上,使用贝叶斯定理构建算法,在文本处理中广泛使用

  • 优点:在数据较少的情况下仍然有效,可以处理多分类问题

  • 缺点:对于输入数据的准备方式较为敏感

  • 适用类型:标称型数据。标称型数据是指标称型目标变量的结果只在有限目标集中取值,如或者只存在(标称型目标变量主要用于分类)

  • 贝叶斯公式

      朴素贝叶斯算法_第1张图片
    • 知识扩展

      在条件概率中,已知事件B出现的条件下A出现的概率,称为条件概率,记作P(A|B)

        朴素贝叶斯算法_第2张图片

      很明显,贝叶斯公式的推导由此而生

       
  • 朴素贝叶斯公式:但是在条件独立的情况下,将X分割成X1,X2,X3,....,那么朴素贝叶斯公式就是朴素贝叶斯公式

     
  • 词袋模型:详细解释朴素贝叶斯公式

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    X1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
    X2 S M M S S S M M L L L M M L L
    Y -1 -1 1 1 -1 -1 -1 1 1 1 1 1 1 1 -1
    • 问题:给定的x=(2, S)是属于哪种类别

    • 计算先验概率

       
    • 计算各种条件概率

       
    • 朴素贝叶斯算法_第3张图片
    • 对于给定的x=(2, S),计算

       

      由于分母相同,暂不计算,当Y分别等于1和-1

        朴素贝叶斯算法_第4张图片
    • 根据值的大小判定类别,x=(2, S)属于-1

  • 朴素贝叶斯的三种模型

    • 多项式模型:当特征是离散的时候,使用多项式模型。多项式模型在计算先验概率,P(yk)和条件概率P(xi|yk)时,会做一些平滑处理,该模型常用于文本分类,具体公式

       

      N是总体样本个数,k是总的类别个数,Nyk是类别为yk样本个数,α是平滑值

       

      Nyk是类别为yk的样本个数,n是特征的维数,Nykxi是类别为yk的样本中,第i维特征的值是xi的样本个数,α是平滑值。当α=1时,称作Laplace平滑,0<α<1时,称作Lidstone平滑,当α=0时,不做平滑,但是如果不做平滑,当某一维特征值xi没在训练样本中出现过时,会导致P(xi|yk)=0,从而后验概率为0,加上平滑可以克服这个问题。

    • 伯努利模型:在伯努利模型中,对于一个样本来说,其特征用的是全局的特征。而且每个特征值都是布尔类型。在文本分类中,就是一个特征在文本中是否出现过。如果特征值xi=1

       

      如果特征值xi=0

       

      这就意味着 没有某个特征 也是一个特征

    • 混合模型:

    •  

  • 编码实现

    import numpy as np
    ​
    ​
    class MyBayes:
        def __init__(self):
            # 文本数据集,数据可修改
            self.trainData = [   # 每一个列表表示文本中的一行
                ["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"],
            ]
            # 对应标签,数据可修改
            self.labels = [0, 1, 0, 1, 0, 1]
            # 定义一个词条列表
            self.vocabList = self.create_vocabulary_list()
            # 定义一个词条向量矩阵
            self.vectorMatrix = self.words_to_vec()
    ​
        def create_vocabulary_list(self):
            """
            构建词条集,将trainData中出现过的所有单词构建一个集合
            :return:
                vocabSet: 词条集合,包含dataSet出现过的单词
            """
            vocab = set([])
            for document in self.trainData:
                # 返回前后集合的并集
                vocab = vocab | set(document)
            return list(vocab)
    ​
        def words_to_vec(self):
            """
            文本转换向量矩阵
            :return: 二维列表
            """
            vector_matrix = [self.word_to_vec(words) for words in self.trainData]
            return vector_matrix
    ​
        def word_to_vec(self, words):
            """
            文本中的一行转换向量矩阵
            使用伯努利模型将数据进行数值化转换,构建一个与vocabList大小一致的数值列表
            扫描inputSet,如果inputSet中的单词出现在vocabList中则数值列表对应的位设置为1,否则为0
            :param words: 一句话中单词组成的单词列表
            :return: vec数值化后0,1组成的列表
            """
            vec = [0]*len(self.vocabList)
            for word in words:
                if word in self.vocabList:
                    vec[self.vocabList.index(word)] = 1
                else:
                    print("The word '{}' is not in my vocabulary!".format(word))
            return vec
    ​
        def naive_bayes_cal(self):
            """
            朴素贝叶斯计算
            计算所有类别概率
            计算每个类别下每个词条出现的条件概率
            为防止向下溢出(多个小于1的概率相乘四舍五入为0),结果采用对数(乘法变加法)计算
            0表示正常性评论,1表示简单性评论
            :return:
                p0Vec: 所有分类为0的文本中每个词条出现的条件概率
                p1Vec: 所有分类为1的文本中每个词条出现的条件概率
                pAbusive: 分类为1的文本的概率
            """
            # 文档总数,词条总数
            doc_nums, word_nums = len(self.vectorMatrix), len(self.vectorMatrix[0])
            # 简单性评论概率
            p_abusive = sum(self.labels) / float(doc_nums)
            # 正常性、简单性评论词频统计
            p0_num, p1_num = np.ones(word_nums), np.ones(word_nums)
            # 正常性、简单性评论中出现的总词条数,作为计算条件概率的分母
            p0_sum, p1_sum = 2.0, 2.0for i in range(doc_nums):
                if self.labels[i] == 0:
                    p0_num += self.vectorMatrix[i]
                    p0_sum += sum(self.vectorMatrix[i])
                else:
                    p1_num += self.vectorMatrix[i]
                    p1_sum += sum(self.vectorMatrix[i])
            p0_vec = np.log(p0_num / p0_sum)
            p1_vec = np.log(p1_num / p1_sum)
            return p0_vec, p1_vec, p_abusive
    ​
        def naive_bayes_classify_global(self):
            """
            分类测试,测试文本所有行
            :return:
            """
            d = {str(self.trainData[i]): self.naive_bayes_classify(self.vectorMatrix[i]) for i in range(len(self.labels))}
            for key, value in d.items():
                print("{} res is {}".format(key, value))
    ​
        def naive_bayes_classify(self, word):
            """
            分类测试
            :param word: 测试文本中的一行
            :return: 类别为0或者1
            """
            p0_vec, p1_vec, p_class1 = self.naive_bayes_cal()
            p0 = sum(word*p0_vec) + np.log(1-p_class1)
            p1 = sum(word*p1_vec) + np.log(p_class1)
            return 1 if p1 > p0 else 0
    ​
    ​
    if __name__ == '__main__':
        my_bayes = MyBayes()
        # my_bayes.naive_bayes_classify_global()
        doc = ["how", "to", "stop", "him", "my", "steak", "dog"]
        docVec = my_bayes.word_to_vec(doc)
        res = my_bayes.naive_bayes_classify(docVec)
        print("{} is {}".format(doc, res))

你可能感兴趣的:(朴素贝叶斯算法)