- C1,C2....两两互斥,即 Ci ∩ Cj = ∅ ,i≠j , i,j=1,2,....,且P(Ci)>0,i=1,2,....;
- C1∪C2∪....=Ω ,则称事件组 C1,C2,...是样本空间Ω的一个划分
- 一部分同学认为P(A)=1/5
- 另外一部分人认为,P(A)与B是否发生有关系,如果B发生了,则P(A)=1/9,如果B没有发生,则P(A)=2/9
- 如果P1(x,y)>P2(x,y),那么点A类别为1
- 如果P1(x,y)<P2(x,y),那么点A类别为0
- 对于图中数据,给出一个新数据点进行划分,KNN最大的问题就是计算量很大,每次对新的数据点进行划分,都要进行1000次距离计算(假设有1000个数据点)
- 而如果用决策树的话,面临最大的问题是:如果划分属性,也就是要沿着X轴与Y轴进行划分数据(将连续数据变为离散数据)
- 如果采用贝叶斯的话,只需要计算该数据点属于每个类别的概率(上图只需要计算2次),然后进行比较即可
- 给定X,可以通过直接建模P(C| A)来预测C(当然是有数据集样本的),这样得到的是“判别式模型”(discriminative models)
- 给定X,也可以先对联合概率分布P(A,C)建模,然后再由此获得P(C | A),这样得到的是“生成式模型”(generative models)
- 画红线部分P(C)被称为先验概率(Prior probability)或者似然,也就是在事件A发生之前,我们就对C事件概率的一个判断
- 画黑线部分P(C|A)被称为后验概率(Posterior probability),也就是在事件A发生后,我们队C事件概率的重新评估
- 画蓝线部分被称为可能性函数(Likelyhood),这是一个调整因子,使得预估概率更接近真实概率
- 第一步:通过样本数据来估计类别的概率分布(也就是得到各个参数,概率分布本来就是一个数学公式,其中你知道概率分布的类别,再知道其中的关键参数,就知道了整个分布公式)
- 第二步:既然知道了概率分布,那么就算出要分类的数据点,属于每个类别的概率即可
- 第三步:对每个类别概率进行比较,选择概率最大的,然后将类别分给该数据点即可
- 频率主义学派(Frequentisit,也就是古典概率学派):认为参数虽然未知,但是却是客观存在的固定值,因此,可通过优化似然函数等准则来确定参数值
- 贝叶斯学派(Bayesian,后来发展出来的学派):认为参数是未观察到的随机变量,其本身也也可以有分布,因此,可假定参数服从一个先验分布,然后基于观测到的数据来计算参数的后验分布。
颜值
|
技术
|
信用
|
是否录用
|
高
|
大牛
|
好
|
肯定录用
|
高
|
菜鸡
|
好
|
考虑考虑
|
低
|
大牛
|
好
|
肯定录用
|
高
|
中庸
|
差
|
考虑考虑
|
高
|
大牛
|
差
|
考虑考虑
|
低
|
中庸
|
差
|
肯定不录用
|
低
|
菜鸡
|
好
|
考虑考虑
|
- P(肯定录用 | 高,中庸,好),P(考虑考虑 | 高,中庸,好)和P(肯定不录用 | 高,中庸,好),三个概率哪个大,大的那个就是分类结果了
- P(高,中庸,好 | 肯定录用) = P(高 | 肯定录用)* P(中庸 | 肯定录用) * P(好 |肯定录用)
- P(高,中庸,好)= P(高)* P(中庸)* P(好)
- P(高 | 肯定录用) = 1/2 (肯定录用样本一共有2个,其中颜值为高的,只有1个)
- P(中庸| 肯定录用) = 0 /2 = 0 (肯定录用样本中,没有技术中庸的,所以为0)
- P(好 | 肯定录用) = 2/2 =1
- P (肯定录用)= 2/7 (一共有7条数据,其中肯定录用的有两条)
- P(高)= 4/7
- P (中庸)= 2/7
- P(好) = 4/7
- P(肯定录用 | 高,中庸,好) = 0
- P(考虑考虑 | 高,中庸,好) = 147/256
- P(肯定不录用 |高,中庸,好)= 0
- 算法逻辑简单,就是依赖一个贝叶斯定理公式,剩下的就是小学水平的四则运算了
- 分类过程开销很小,因为假设所有属性都相互独立,所以将所有属性都单独求概率,不会有联合概率
- 首先,属性间相互独立这个前提在现实生活中,是很少见的,往往不成立,所以在属性个数比较多或者属性之间关系比较大的时候,朴素贝叶斯分类效果不是很好
- 朴素贝叶斯中朴素二字的含义
- 为什么要假设所有属性相互独立呢?
- 实际编程中
二、实战之实现言论过滤(简单算法)
1、问题描述(在线社区留言板)
为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用而来负面或者侮辱性的语言,那么就将该留言标识为内容不当,过滤这类内容是一个很常见的需求,对此问题建立两个类别:侮辱类和非侮辱类,使用1和0表示(即,用1表示侮辱,用0表示非非侮辱)。
主要思路:给你大量的样本语句(同时每个语句附带标签,比如这句话是侮辱还是非侮辱)
- 那么我们首先要对每条语句进行词条分割,也就是将一个语句分成一个个的词(比如“我是男人”,转换成“我”“是”“男人”)
- 然后我们要对生成的词条数据集进行去重(也就将重复的词条去掉),变成一个词汇表
- 制成词汇表以后,我们要根据语句的标签,对每个单词进行概率的确定(比如单词“男人”,它属于侮辱词的概率为多少,非侮辱词汇的概率为多少,注意这两个数值和为1)
- 好了,上面三步是训练步骤,也就是我们可以根据数据集训练得到词汇表中每个词属性的先验概率
- 根据先验概率,再给我们一条新的语句,我们就可以判断这条语句属于侮辱语句的概率是多少了(如果属于侮辱语句的概率大于非侮辱语句,则判断该语句为侮辱语句)
2、直接上代码
# -*- coding: UTF-8 -*-
import numpy as np
from functools import reduce
"""
函数1:创建实验样本
功能说明:首先要将文本切分成词条,这个函数就是干这个用的不过,现在已经切好了
返回值说明:postingList就是词条,classVec则是词条对应的分类标签
"""
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']]
classVec = [0,1,0,1,0,1] #类别标签向量,1代表侮辱性词汇,0代表不是
return postingList,classVec #返回实验样本切分的词条和类别标签向量
"""
函数2: 制作词汇表
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表
参数说明:dataSet就是上面的postingList,也就是重复的词条样本集,而vocabSet则是无重复的词汇表
"""
def createVocabList(dataSet):
vocabSet = set([]) #创建一个空的不重复列表
for document in dataSet:
vocabSet = vocabSet | set(document) #取并集
return list(vocabSet)
"""
函数3:词汇向量化
函数说明: 根据vocabList词汇表(也就是上面函数制作的词汇表),将inputSet(你输入的词汇)向量化,
向量的每个元素为1或0,如果词汇表中有这个单词,就置1;没有,就置0
参数说明:最后返回的是文档向量(不是0就是1)
"""
def setOfWords2Vec(vocabList,inputSet):
returnVec = [0] * len(vocabList) # 创建一个其中所含元素都为0的向量
for word in inputSet: #遍历每个词条
if word in inputSet: #如果词条存在于词汇表中,则置1
returnVec[vocabList.index(word)] = 1
else:
print("词汇:%s 并没有在词汇表中" % word) # 词汇表中没有这个单词,表示出现了问
return returnVec #返回文档向量
"""
函数4:朴素贝叶斯分类器训练函数
函数说明: 利用朴树贝叶斯求出分类概率,也可以说是求出先验概率
参数说明:
输入参数trainMatrix:是所有样本数据矩阵,每行是一个样本,一列代表一个词条
输入参数trainCategory:是所有样本对应的分类标签,是一个向量,维数等于矩阵的行数
输出参数p0Vect:是一个向量,维数与上面相同,每个元素表示对应样本属于侮辱类的概率
输出参数p1Vect:是一个向量,和上面那个向量互补(因为是二分类问题),每个元素对应样本属于非侮辱类的概率
输出参数pAbusive:是一个概率值,表示这篇文档(所有样本的综合)属于侮辱类的概率
"""
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) #训练集中样本数量
numWords = len(trainMatrix[0]) #每条样本中的词条数量
pAbusive = sum(trainCategory)/float(numTrainDocs) #文档属于侮辱类的概率
p0Num = np.zeros(numWords); p1Num = np.zeros(numWords) #创建numpy.zeros数组(维度和numWords一样,但元素全是0)
p0Denom = 0.0; p1Denom = 0.0 #分母初始化为0.0
for i in range(numTrainDocs):
if trainCategory[i] == 1: #统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else: #统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = p1Num/p1Denom #相除
p0Vect = p0Num/p0Denom
return p0Vect,p1Vect,pAbusive #返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率
"""
函数5:朴素贝叶斯分类器分类函数
函数说明: 利用几个函数得到的结果,直接对vec2Classify进行分类,说白了就是利用贝叶斯定理来求了,注意这里没有用到分母,直接求的分子
参数说明:
输入参数vec2Classify——要分类的向量
输入参数后面三个——就是函数3得到的三个输出向量
输入参数:就是分类结果了(因为分类标签就只有2个,如果更改数据的话,这里要改一下)
"""
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1 = reduce(lambda x,y:x*y, vec2Classify * p1Vec)*pClass1 #对应元素相乘,相同为1,不同为0
p0 =reduce(lambda x,y:x*y, vec2Classify*p0Vec)*(1.0-pClass1)
print('p0:',p0)
print('p1:',p1)
if p1>p0:
return 1
else:
return 0
"""
函数6:测试朴素贝叶斯分类器
函数说明: 这个就是一个测试函数了
"""
def testingNB():
listOPosts,listClasses = loadDataSet() #创建实验样本
myVocabList = createVocabList(listOPosts) #创建词汇表
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc)) #将实验样本向量化
p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses)) #训练朴素贝叶斯分类器
testEntry = ['love', 'my', 'dalmation'] #测试样本1
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) #测试样本向量化
if classifyNB(thisDoc,p0V,p1V,pAb):
print(testEntry,'属于侮辱类') #执行分类并打印分类结果
else:
print(testEntry,'属于非侮辱类') #执行分类并打印分类结果
testEntry = ['stupid', 'garbage'] #测试样本2
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) #测试样本向量化
if classifyNB(thisDoc,p0V,p1V,pAb):
print(testEntry,'属于侮辱类') #执行分类并打印分类结果
else:
print(testEntry,'属于非侮辱类') #执行分类并打印分类结果
if __name__ == '__main__':
testingNB()
3、上述算法函数分析
(1)函数1:创建实验样本
这个就相当简单了,将训练样本语句分割成一个个词条(注意这是重复的),返回词条矩阵和标签向量
(2)函数2:制作词汇表
最后生成的词汇表不再是矩阵,而是一个单纯的列表,依次列举了所有的单词,如下图所示:
(3)函数3:词汇向量化
这个函数有两个参数vocabList和inputSet,第一个参数vocabList就是词汇表,而inputSet则是一句输入单词向量(),举个例子,我输入的vacabList(就是上面的词汇表)为:
输入的inputSet为:
最后输出结果(即returnVec)是:
上面标1的表示,在词汇表的这些位置的单词,你的inputSet语句中都曾经有,而标有0的位置表示没有出现过
注意:这里的1表示的是——出现过,而不是出现次数,这里你无论出现多少次,只要出现就是1,没有出现就是0,不会出现大于1的情况
(4)函数4:朴素贝叶斯分类器训练函数
这个函数说白了就是将你所有样本语句中的词汇都训练一下,看看这些词汇哪些属于侮辱类的词汇(当然得到的是概率值),里面涉及到几个参数,这里讲解一下
输入参数:
- trainMatrix:这是一个矩阵,表示的是所有样本转换为向量后的结果,如下图所示:
- trainCategory:这是标签,也就是上面每个向量对应的标签(其中1表示侮辱,0表示非侮辱),如下图:
函数内部的变量参数:
- p1Num:这是一个向量,记录了词汇表中标签为侮辱类语句中词汇,在词汇表中出现的次数,显示结果如下:
上述列出的数据集中,一共有六个数据样本,但是标有侮辱标签也就是1的,只有三个,找出这三个语句,然后将其词汇按照词汇表一一对照,有一个词,就在那个词上数量,加1,最后就得到上面的p1Num向量
- p1Denom:这就是一个数字,也就是上面p1Num中所有数字的和,当前值为19,
- p1Vect:这是上面两个数相除的结果,最后是一个向量,大部分都是0
- p0Num、p0Denom和p0Vect原理同上,只不过是换了个标签而已
输出参数:
- p0Vect和p1Vect上面已经说了,这里就不再说了
- pAbusive是指样本集标签(0,1,0,1,0,1)中,侮辱类的词条占所有词条的比例(也可以说是概率),也就是标1的标签占所有标签的概率(3/6=0.5)
(5)函数5:朴素贝叶斯分类器分类函数
这个函数是上面4个函数的综合运用,主要功能就是你给我一条语句,然后我将这条语句划分成一个个词条,然后根据我拥有的带有标签的样本数据集得到的模型参数(也就是各种先验概率),计算这条语句属于侮辱类语句的概率和非侮辱类的概率,然后取两者大的概率为其分类标签
输入参数:
- vec2Classify:这是一个向量,是你给我的语句(也就是要分类的语句),然后我经过函数3转换得到的词汇向量(有几个1,就表示这句话有几个单词),我打印了一下:
- p0Vec、p1Vec和pClass1就是函数4得到的三个返回结果(也就是我们训练数据集得到的有用的模型参数)
函数内部参数:
- p1表示这条语句(你给我的,要分类的语句)属于侮辱类语句的概率
- p0表示这条语句(你给我的,要分类的语句)属于非侮辱类语句的概率
困难函数:
- reduce()函数:就是表示累积或者累加,要看第一个参数赋予的运算方式了,详情可以参考——Python中reduce详解
(6)函数6:测试朴素贝叶斯分类器
这个函数其实属于函数5的升级版,虽然函数5也可以对一条语句进行分类,但是运行函数5要进行语句的预处理,因为函数5的输出参数并不是我们直接就有的,而是要通过运行上面前4个函数才可以得到,所以所以说函数6是总领的作用,将前5个函数都综合起来
当然,这是一个简单的测试函数,测试语句都是自己写在代码中的,如果要运用到现实生活中,肯定是不能这么写的,因为测试数据集往往是比较大的,要程序自己会读取文本才可以,下一个实例,我们会再讲如何进行,这个实例只是简单的将朴素贝叶斯的算法框架得了出来
(7)显示结果:
- 解决方法:将所有词出现次数初始化为1,并将分母初始化为2,这样就避免了0概率的出现,这种做法叫做拉普拉斯平滑(Laplace Smoothing),又被称为加1平滑
(1)首先,要改进函数4,也就是trainNB0(trainMatrix,trainCategory),因为这个函数中有分子和分母初始化的步骤,具体改动如下:
"""
函数4:朴素贝叶斯分类器训练函数
函数说明: 利用朴树贝叶斯求出分类概率,也可以说是求出先验概率
参数说明:
输入参数trainMatrix:是所有样本数据矩阵,每行是一个样本,一列代表一个词条
输入参数trainCategory:是所有样本对应的分类标签,是一个向量,维数等于矩阵的行数
输出参数p0Vect:是一个向量,维数与上面相同,每个元素表示对应样本属于侮辱类的概率
输出参数p1Vect:是一个向量,和上面那个向量互补(因为是二分类问题),每个元素对应样本属于非侮辱类的概率
输出参数pAbusive:是一个概率值,表示这篇文档(所有样本的综合)属于侮辱类的概率
"""
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
p0Num = np.ones(numWords);p1Num = np.ones(numWords) #词条初始化次数为1,避免出现0的情况,拉普拉斯平滑第一步
p0Denom = 2.0; p1Denom = 2.0 #分母初始化为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 = np.log(p1Num/p1Denom) #相除,然后取对数,防止下溢出
p0Vect = np.log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
上图中,我只对有更改的地方写了注释,其他地方,你们可以看上面的,避免看的干扰
(2)这一步更改函数5,因为取对数后,我们最后的乘积方式也要改变一下
"""
函数5:朴素贝叶斯分类器分类函数
函数说明: 利用几个函数得到的结果,直接对vec2Classify进行分类,说白了就是利用贝叶斯定理直接求了
但是这里并没有求分母,因为要比较的概率中分母都一样,可以不用求分母
参数说明:
输入参数vec2Classify——要分类的向量
输入参数后面三个——就是函数3得到的三个输出向量
输入参数:就是分类结果了(因为分类标签就只有2个,如果更改数据的话,这里要改一下)
"""
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1 = sum(vec2Classify*p1Vec) + np.log(pClass1) #对应元素相乘,log(A*B)=logA + logB
p0 =sum(vec2Classify*p0Vec) + np.log(1.0-pClass1)
print('p0:',p0)
print('p1:',p1)
if p1>p0:
return 1
else:
return 0
(3)好了,这里再贴一下最终改版:
# -*- coding: UTF-8 -*-
import numpy as np
from functools import reduce
"""
函数1:创建实验样本
功能说明:首先要将文本切分成词条,这个函数就是干这个用的不过,现在已经切好了
返回值说明:postingList就是词条,classVec则是词条对应的分类标签
"""
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']]
classVec = [0,1,0,1,0,1] #类别标签向量,1代表侮辱性词汇,0代表不是
return postingList,classVec #返回实验样本切分的词条和类别标签向量
"""
函数2: 制作词汇表
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表
参数说明:dataSet就是上面的postingList,也就是重复的词条样本集,而vocabSet则是无重复的词汇表
"""
def createVocabList(dataSet):
vocabSet = set([]) #创建一个空的不重复列表
for document in dataSet:
vocabSet = vocabSet | set(document) #取并集
return list(vocabSet)
"""
函数3:词汇向量化
函数说明: 根据vocabList词汇表(也就是上面函数制作的词汇表),将inputSet(你输入的词汇)向量化,
向量的每个元素为1或0,如果词汇表中有这个单词,就置1;没有,就置0
参数说明:最后返回的是文档向量(不是0就是1)
"""
def setOfWords2Vec(vocabList,inputSet):
returnVec = [0] * len(vocabList) # 创建一个其中所含元素都为0的向量
for word in inputSet: #遍历每个词条
if word in inputSet: #如果词条存在于词汇表中,则置1
returnVec[vocabList.index(word)] = 1
else:
print("词汇:%s 并没有在词汇表中" % word) # 词汇表中没有这个单词,表示出现了问
return returnVec #返回文档向量
"""
函数4:朴素贝叶斯分类器训练函数
函数说明: 利用朴树贝叶斯求出分类概率,也可以说是求出先验概率
参数说明:
输入参数trainMatrix:是所有样本数据矩阵,每行是一个样本,一列代表一个词条
输入参数trainCategory:是所有样本对应的分类标签,是一个向量,维数等于矩阵的行数
输出参数p0Vect:是一个向量,维数与上面相同,每个元素表示对应样本属于侮辱类的概率
输出参数p1Vect:是一个向量,和上面那个向量互补(因为是二分类问题),每个元素对应样本属于非侮辱类的概率
输出参数pAbusive:是一个概率值,表示这篇文档(所有样本的综合)属于侮辱类的概率
"""
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) #训练集中样本数量
numWords = len(trainMatrix[0]) #每条样本中的词条数量
pAbusive = sum(trainCategory)/float(numTrainDocs) #文档属于侮辱类的概率
p0Num = np.ones(numWords);p1Num = np.ones(numWords) #词条初始化次数为1,避免出现0的情况,拉普拉斯平滑第一步
p0Denom = 2.0; p1Denom = 2.0 #分母初始化为2.0,拉普拉斯平滑第二步
for i in range(numTrainDocs): #对每个标签进行判断
if trainCategory[i] == 1: #统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else: #统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = np.log(p1Num/p1Denom) #相除,然后取对数,防止下溢出
p0Vect = np.log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive #返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率
"""
函数5:朴素贝叶斯分类器分类函数
函数说明: 利用几个函数得到的结果,直接对vec2Classify进行分类,说白了就是利用贝叶斯定理直接求了
但是这里并没有求分母,因为要比较的概率中分母都一样,可以不用求分母
参数说明:
输入参数vec2Classify——要分类的向量
输入参数后面三个——就是函数3得到的三个输出向量
输入参数:就是分类结果了(因为分类标签就只有2个,如果更改数据的话,这里要改一下)
"""
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1 = sum(vec2Classify*p1Vec) + np.log(pClass1) #对应元素相乘,log(A*B)=logA + logB
p0 =sum(vec2Classify*p0Vec) + np.log(1.0-pClass1)
print('p0:',p0)
print('p1:',p1)
if p1>p0:
return 1
else:
return 0
"""
函数6:测试朴素贝叶斯分类器
函数说明: 这个就是一个测试函数了
"""
def testingNB():
listOPosts,listClasses = loadDataSet() #创建实验样本
myVocabList = createVocabList(listOPosts) #创建词汇表
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc)) #将实验样本向量化
p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses)) #训练朴素贝叶斯分类器
testEntry = ['love', 'my', 'dalmation'] #测试样本1
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) #测试样本向量化
if classifyNB(thisDoc,p0V,p1V,pAb):
print(testEntry,'属于侮辱类') #执行分类并打印分类结果
else:
print(testEntry,'属于非侮辱类') #执行分类并打印分类结果
testEntry = ['stupid', 'garbage'] #测试样本2
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) #测试样本向量化
if classifyNB(thisDoc,p0V,p1V,pAb):
print(testEntry,'属于侮辱类') #执行分类并打印分类结果
else:
print(testEntry,'属于非侮辱类') #执行分类并打印分类结果
if __name__ == '__main__':
testingNB()
然后输出结果:
这里输出为什么是负数呢?因为我们最后都采用了对数,那几个相乘的元素都是小于1的,自然是负数,负数相加最后自然也是负数了!这个问题可以参考上面的ln函数图!
- 上面那个拉普拉斯平滑时,分母初始化为2,并不是所有的问题都是初始化为2,这个要根据你的数据集的类别数量来进行修改,这个只有两个类别:侮辱和非侮辱,所以分母是2,如果类别是3,则就要改为3了,这个问题可以参考西瓜书,上面有详细的公式解释
- 这个算法虽然已经算是完善了,但是还有一步没有搞定,那就数据集的读取问题,我们上面最终版依然还是自己在代码内部写的数据集,这样还是不行的,下一个博客,我们再进行修改完善,同时也再实现几个例子
1、IndentationError: unindent does not match any outer indentation level
截图如下:
说白了,就是粘贴复制代码的时候,有些tab键和空格搞混了,缩进的问题,具体解决方案:解决问题
当然,我用的是Pycharm,所以上面那个解决方面没有什么用,我直接将那个出问题的代码重新自己写了一遍,这才搞定了,以后如果遇到解决方案,会在这里写出来的。
四、资源
五、资源参考
1、西瓜书:链接:https://pan.baidu.com/s/1ozCZb-912fB2auyAGRcNmw 密码:3wg2
2、首先自然是《机器学习实战》这本电子书了,链接为:链接:https://pan.baidu.com/s/1nfJuwI2JQ6OAjM5Jbi7MOg 密码:l5xv(高清彩色版本)
3、这本书附带的源代码与数据集(这里的源代码是这本书附带的,不是我上面写的,有一部分是Python2格式):链接:https://pan.baidu.com/s/1mDqTlRVPAZBkok4E7ToVHQ 密码:162r
4、一些参考书:
用Python做科学计算:链接:https://pan.baidu.com/s/1hEwKT4k3jAqEDslla2L1eQ 密码:0k5l
笨方法学Python:链接:https://pan.baidu.com/s/1MKCKoRZjPV0Q4rQoa2LEpg 密码:enfk
流畅的Python:链接:https://pan.baidu.com/s/1Ln28HA3ITarp4sCPtT85VA 密码:elpc