朴素贝叶斯算法以及案例

您所在的位置:网站首页 朴素贝叶斯算法举例 朴素贝叶斯算法以及案例

朴素贝叶斯算法以及案例

2024-07-09 00:20| 来源: 网络整理| 查看: 265

朴素贝叶斯算法以及案例 大家好,我是W

这次给大家带来朴素贝叶斯算法,贝叶斯分类是一类分类算法的总称,其基础都是贝叶斯定理。要理解该算法就需要先理解其背后的概率知识,我会尽量详细地给大家讲解清楚。所以今天的顺序是:贝叶斯理论和条件概率、朴素贝叶斯原理、案例 - insultingComments分类。

Bayes贝叶斯理论

假设在坐标轴中存在两类点,分别对应着两个类别。接下来我们要对新加入的点进行分类,我们要怎么做?可能会联想到之前的KNN算法,这也是一个思路。但是在这里可以考虑使用贝叶斯决策:即我们可以认为新加入的点既可以属于A类,也可以属于B类,但是分别对应着不同的概率。那么当别人问起这个点到底属于A还是属于B时,我们会倾向回答概率大的类别。这就是贝叶斯决策理论的思想:选择具有最高概率的决策。

条件概率 p(A)

P(A) - 事件A发生的概率,比如P(抛硬币出正面) = 1/2

P(A|B)

P(A|B) - 事件B发生的情况下A发生的概率。这个就有讲头了,下图两个方格表示两个黑盒子,里面放有白色和黄色乒乓球若干,求在右桶中抽出白球的概率。那么我们就有两种算法:

法1

首先,要求得右桶白球占总球数的比例,P(右桶白球数/总球数) = 1/7。然后求出右桶球数占总球数的比例,P(右桶球数/总球数) = 2/7。于是右桶中抽出白球的概率,P(抽出白球|从右桶中抽) = P(右桶白球数/总球数) / P(右桶球数/总球数) = 1/2。

法2

使用贝叶斯准则求条件概率,贝叶斯准则可以帮助我们交换条件概率的条件和结果,即若一直P©、P(x)、P(x|c)那么就可以求P(c|x) = P(x|c)P© / P(x)。在本题中若已知P(从右桶中抽|已知抽中白球)、P(选中右桶概率)、P(抽中白球概率),就可以算出P(抽出白球|从右桶中抽)。

在这里插入图片描述

有人可能疑问,我若是能求出P(x|c)我还用怕求不出来P(c|x)?其实我们真的可以求出P(x|c)而求不出P(c|x),所以需要依靠贝叶斯转换条件和结果的特性,我会在后面的实战案例环节讲解。

朴素贝叶斯

在条件概率部分已经知道贝叶斯准则的公式,即P(c|x) = P(x|c)P© / P(x),但是在实际场景下,例如文本分类,每一个样本会存在多个特征。假设这些特征相互独立,即在统计意义上独立,则这个假设就是朴素贝叶斯分类器中的朴素的含义,朴素贝叶斯分类器还有一个假设是所有特征重要程度相同。

接上一段,因为每个样本会存在许多特征,所以公式可以改写成:

P(c|(w_1,w_2,w_3,…,w_n)) = P((w_1,…,w_n)|c)P© / P(w_1,w_2,…,w_n) ,w_n表示样本的多维特征。

又因为朴素贝叶斯中每个样本的每个特征相互独立,所以有:

P((w_1,…,w_n)|c) = P(w_1|c) * … * P(w_n|c)

请大家先记住以上结论,后面会用到,也会随时返回来。

案例 - insultingComments分类

项目描述: 论坛需要对用户的评论做质量监控,以确保提供给用户一个干净的论坛环境。所以需要对用户评论做分类,若用户评论内容包含负面或侮辱性内容,则为内容不当。因此建立一个二分类问题:侮辱性言乱和非侮辱性言论。

开发流程:

流程解释准备数据实际场景应该是公司数据库提供,本案例假设已经得到一些评论数据,并且带有标签,以字符串存储分析数据对bayes算法的计算做准备工作,例如将数据集转为可计算类型训练算法这一步会产生一系列bayes算法参数,用于实际使用测试数据自己定义若干条评论测试是否符合预期 准备数据

OK,按照上面的流程,这一步准备数据我们假设已经从后台拿到处理好的数据,并且带有相应的标签,格式是字符串,写一个函数把数据返回。

def loadDataSets(): """ 加载数据集 :return: dataMatrix,labelList """ dataMatrix = [ ["stop", "fuck", "you", "bitch", "garbage"], ["useless", "dog", "stupid", "worthless"], ["suck", "my", "dick", "bitch", "pig", "asshole"], ["son", "bitch", "hoocker", "happy"], ['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'], ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'], ] labelList = [1, 1, 1, 1, 0, 0, 0] return dataMatrix, labelList

这里直接把字符串拆成列表了,如果大家想还原更真实的场景可以考虑使用结巴分词来做。

分析数据

在这一阶段我们需要把字符串转为可以运算的类型,那么我们需要按照以下步骤做:

得到trainingSet的所有字符的去重列表把dataMatrix转为one-hot矩阵 1’ 得到去重列表

显然该函数只需要dataMatrix矩阵就可以,无论用什么方法只需要做到去重,转换成列表就可以了。下面这个方法时我找到写法十分简洁的方法:

def buildWordsSet(dataMatrix): """ 创建单词集合 :param dataMatrix: 单词矩阵 :return: """ # 定义一个空set,因为set本身有去重的功能 wordsSet = set([]) # 遍历矩阵的每一行 for comment in dataMatrix: # |表示取交集 wordsSet = wordsSet | set(comment) return list(wordsSet) 2’ 把dataMatrix转为one-hot

因为转为one-hot所以需要1’中的去重列表,所以传入dataMatrix和wordsSet。这样的操作是可以的,但是考虑到后期在测试阶段会存在单个列表而非矩阵转one-hot,所以我们考虑在调用函数时遍历dataMatrix,对每一行做处理。

def getOneZeroVector(wordSet, comment): """ 以wordSet这个训练集词频向量为依据构建comment的词频(0,1)向量 :param wordSet: 全集 :param comment: 单个评论的list :return: 每个comment对应的(0,1)向量 """ one_zero_vec = [0] * len(wordSet) for word in comment: if word in wordSet: one_zero_vec[wordSet.index(word)] = 1 else: print(" %s 没有收录" % word) return one_zero_vec 训练算法

在这一阶段就需要通过使用bayes公式得到一些参数,为接下来的使用做准备。并且在这一阶段就是整个算法的核心步骤,我也尽量给大家讲清楚。

目前,我们有的变量是:

dataMatrix [['stop', 'fuck', 'you', 'bitch', 'garbage'], # 1 ['useless', 'dog', 'stupid', 'worthless'], # 1 ['suck', 'my', 'dick', 'bitch', 'pig', 'asshole'], # 1 ['son', 'bitch', 'hoocker', 'happy'], # 1 ['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], # 0 ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],# 0 ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him']]# 0 labelList [1, 1, 1, 1, 0, 0, 0] wordSet ['son', 'mr', 'licks', 'him', 'dick', 'garbage', 'hoocker', 'useless', 'dalmation', 'steak', 'problems', 'to', 'help', 'my', 'cute', 'how', 'I', 'bitch', 'worthless', 'stupid', 'is', 'you', 'love', 'so', 'suck', 'stop', 'ate', 'pig', 'asshole', 'has', 'fuck', 'please', 'dog', 'flea', 'happy'] np.array(one_zero_matrix)

one_zero_matrix是dataMatrix转为one-hot后的矩阵。

[[0 1 0 1 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 1 0] [0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0] [1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1] [0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0]] 重温bayes公式

不了解的同学推荐用草稿写下来,看得清楚点,电脑的格式不好看。

P(c|x) = P(x|c)P(c) / P(x)

在朴素贝叶斯标题下我们了解了一个样本可能会有多个特征,所以我们往往用w来代替x,故

P(c|x) = P(x|c)P(c) / P(x)** = **P(c|w) = P(w|c)P(c) / P(w)

又因w包含多个特征,所以

P(c|x) = P(x|c)P(c) / P(x) = P(c|w) = P(w|c)P(c) / P(w) = P(c|(w_1,w_2,w_3,...,w_n)) = P((w_1,...,w_n)|c)P(c) / P(w_1,w_2,...,w_n)

又因为朴素贝叶斯中特征间相互独立,所以

P((w_1,...,w_n)|c) = P(w_1|c)P(w_2|c)....P(w_n|c)

**P(w_1|c)**表示已知该评论为侮辱性评论的情况下出现w_1词的概率是多少。

计算bayes参数代码

那么拿到one_zero_matrix又怎么用呢?

首先,我们可以去计算P(w|c)。遍历矩阵中每一个向量,若该样本向量标记为侮辱性1,则把向量每一维加到空向量中,并且计数该向量词语个数。遍历完整个矩阵后,就会得到一条好向量(标签为0的向量在各个维度上的和)和一条坏向量,还有整个trainingSet的好词数(整个训练集标签为0的评论词语个数)和坏词数。在这个基础上相除就是P(w|c)。

def getBayesParams(one_zero_matrix, labelList): """ 计算贝叶斯公式参数 :param one_zero_matrix: (0,1)词频矩阵 :param labelList: 每个评论的标签 :return: log(词频/好类总词数) , log(词频/坏类总次数) , 侮辱性评论占训练集总评论概率 """ # 侮辱性评论概率 p_c1 = sum(labelList) / float(len(labelList)) # 训练集总词数 total_words_count = len(one_zero_matrix[0]) # 两种单词出现频率列表 p0List = np.ones(len(one_zero_matrix[0])) p1List = np.ones(len(one_zero_matrix[0])) # 计算两类词频 p0num = 1.0 p1num = 1.0 # 遍历所有测试集评论 for i in range(len(labelList)): # 若该评论是侮辱性 if labelList[i] == 1: p1List += one_zero_matrix[i] p1num += sum(one_zero_matrix[i]) else: p0List += one_zero_matrix[i] p0num += sum(one_zero_matrix[i]) # 每个词词频列表/该类别词频 再取对数 p1vec = np.log(p1List / p1num) # 已知是侮辱性评论情况下,每个词出现的概率 p0vec = np.log(p0List / p0num) # 已知不是侮辱性评论情况下,每个词出现的概率 return p1vec, p0vec, p_c1

返回的三个对象分别是P(w|坏评论)、P(w|好评论)、P(坏评论出现概率)

为什么使用np.log()

在重温贝叶斯公式这个部分我们看到,在相互独立的环境下,

P((w_1,...,w_n)|c) = P(w_1|c)P(w_2|c)....P(w_n|c)

但是,每个概率都是远小于1的浮点数,在计算机中如此多的浮点数连乘很可能会出现机器0,即小到一定地步了就没办法保留尾数。所以为了解决这种情况可以转为log函数,log运算可以把连乘转换为加法,防止了机器0的出现。

实现比较代码

按照bayes思想,选择概率大的类别。

def classifyByBayes(p1vec, p0vec, p_c1, one_zero_vector): """ 使用贝叶斯参数比较得出结果 :param p1vec: :param p0vec: :param p_c1: :param one_zero_vector: :return: """ # sum(one_zero_vector * p1vec) 对应元素相乘相加 # p_1 = sum(one_zero_vector * p1vec) + np.log(p_c1) p_1 = sum(one_zero_vector * p1vec) # p_0 = sum(one_zero_vector * p0vec) + np.log(1.0 - p_c1) p_0 = sum(one_zero_vector * p0vec) if p_1 > p_0: return 1 else: return 0 项目地址

点击进入github



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3