作用
贝叶斯 常用来做分类任务。比如 判断 垃圾邮件 ,拼写纠错 等任务。
熟悉以前所学的概念
S:S是样本空间,是所有可能事件的总和。
P(A):是样本空间S中A事件发生的概率,维恩图中绿色的部分。
P(B):是样本空间S中B事件发生的概率,维恩图中蓝色的部分。
P(A∩B):是样本空间S中A事件和B事件同时发生的概率,也就是A和B相交的区域。
P(A|B):是条件概率,是B事件已经发生时A事件发生的概率。
公式
条件 概率 解释:
P(A|B)
已知 B 发生的情况下 A 发生的概率 是多少?
P(“具有某特征”|“属于某类”)
如下图:
我们经常收到邮件 ,邮件中有很多词语 ,我们怎么判断 这个邮件是垃圾邮件呢?
假如 邮件中 含有 买房 , 贷款 ,办理 , 优惠 只含有这4个词 。
那么在条件概率下 分类 :垃圾邮件 , 正常邮件 二分类 。
特征就有: 买房 , 贷款 ,办理 , 优惠 4个特征。
在如下图: 比如 在垃圾邮件中 各个词 出现的次数: 总共加起来都是 10次。为了方便计算。
垃圾邮件:
以下都是约等于 。
P(垃圾邮件) = 22/40= 0.55
P( “”买房“” | 垃圾邮件) = 5 / 22 = 0.22 ;
P( “”办理“” | 垃圾邮件) = 6 / 22 = 0.28 ;
P( “”贷款“” | 垃圾邮件) = 7 / 22 = 0.32 ;
P( “”优惠“” | 垃圾邮件) = 4 / 22 = 0.18;
正常邮件:
P(正常邮件) =18 /40= 0.45
P( “”买房“” | 正常邮件) = 5 / 18 = 0.28 ;
P( “”办理“” | 正常邮件) = 4 / 18 = 0.22 ;
P( “”贷款“” | 正常邮件) = 3 / 18 = 0.17 ;
P( “”优惠“” | 正常邮件) = 6 / 18 = 0.33 ;
全概率公式解释:
全概率公式:P(A)
P( “”买房“”) = P( “”买房“” | 垃圾邮件) * P(垃圾邮件) + P( “”买房“” | 正常邮件) P(正常邮件) = 0.550.22+0.45*0.28 = 0.25
P( “”买房“”) =买房的数字 / 总词 数 = 10/40=0.25
所以计算 应该正确。
贝叶斯 公式 解释:
贝叶斯公式:P(Bi|A)
P( 垃圾邮件 | “”买房“”) 已知 特征 买房 这个词 出现的时候 求 是垃圾邮件的概率?
这是上面的 已知 和未知 反过来 求 分类 。
这也常称为 逆概思想
根据
P( 垃圾邮件 | “”买房“”) = P( “”买房“ | “垃圾邮件”) * P(“垃圾邮件”) / ( p(“买房")) = 0.22 *0.55 / 0.25 = 0.484
这只是根据一个词的 预测 文中 有很多个词。
P( 垃圾邮件 | “”买房“”, “办理“”,“”贷款“”,“”优惠“”) = P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “垃圾邮件”) * P(“垃圾邮件”) / ( p(“”买房“,“”办理“”,“”贷款“”,“”优惠“))
朴素贝叶斯
P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “垃圾邮件”) 这个概率 我们之前 没有求解过 也不知道 求解起来也麻烦 。
假设 各词之间 相互 独立的 。
P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “垃圾邮件”) =P( “”买房“ | “垃圾邮件”) * P( “”办理“ | “垃圾邮件”) * P( “”贷款“ | “垃圾邮件”)* P( “”优惠“ | “垃圾邮件”)
这也称为 : 贝叶斯公式下面的各种特征条件 互相独立 没有影响 就称为 朴素贝叶斯 。
也大大简化了 公式难度。
判断 垃圾还是正常
我们求解 这封邮件 到底是 垃圾 还是 正常 邮件 通过对比:
P( 垃圾邮件 | “”买房“”, “办理“”,“”贷款“”,“”优惠“”) > P( 正常邮件 | “”买房“”, “办理“”,“”贷款“”,“”优惠“”)
表示 为 垃圾邮件 反之 正常邮件 。
因为
P( 垃圾邮件 | “”买房“”, “办理“”,“”贷款“”,“”优惠“”) = P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “垃圾邮件”) * P(“垃圾邮件”) / ( p(“”买房“,“”办理“”,“”贷款“”,“”优惠“))
P( 正常邮件 | “”买房“”, “办理“”,“”贷款“”,“”优惠“”) = P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “正常邮件”) * P(“正常邮件”) / ( p(“”买房“,“”办理“”,“”贷款“”,“”优惠“))
分母 都一样 所以 只用对比 分子 。
P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “垃圾邮件”) * P(“垃圾邮件”) > P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “正常邮件”) * P(“正常邮件”)
根据 朴素贝叶斯:
P( 垃圾邮件 | “”买房“”, “办理“”,“”贷款“”,“”优惠“”) ~= P( “”买房“ | “垃圾邮件”) * P( “”办理“ | “垃圾邮件”) * P( “”贷款“ | “垃圾邮件”)* P( “”优惠“ | “垃圾邮件”) * P(“垃圾邮件”)
P(垃圾邮件) = 22/40= 0.55
P( “”买房“” | 垃圾邮件) = 5 / 22 = 0.22 ;
P( “”办理“” | 垃圾邮件) = 6 / 22 = 0.28 ;
P( “”贷款“” | 垃圾邮件) = 7 / 22 = 0.32 ;
P( “”优惠“” | 垃圾邮件) = 4 / 22 = 0.18;
约等于 0.00195
P( “”买房“,“”办理“”,“”贷款“”,“”优惠“ | “正常邮件”) * P(“正常邮件”)
正常邮件:
P(正常邮件) =18 /40= 0.45
P( “”买房“” | 正常邮件) = 5 / 18 = 0.28 ;
P( “”办理“” | 正常邮件) = 4 / 18 = 0.22 ;
P( “”贷款“” | 正常邮件) = 3 / 18 = 0.17 ;
P( “”优惠“” | 正常邮件) = 6 / 18 = 0.33 ;
约等于 0.00155
0.00195 > 0.00155
所以 当同时 出现
“”买房“”, “办理“”,“”贷款“”,“”优惠“ 这些词的时候 大概上就能猜测是垃圾邮件 。
贝叶斯推断:
贝叶斯推断可以说明贝叶斯定理中两个条件概率之间的关系。换句话说就是我们为什么可以通过P(A|B),P(A),和P(B)三个概率计算出P(B|A)发生的概率。
在贝叶斯推断中,每一种概率都有一个特定的名字:
P(B)是”先验概率”(Prior probability)。
P(A)是”先验概率”(Prior probability),也作标准化常量(normalized constant)。
P(A|B)是已知B发生后A的条件概率,叫做似然函数(likelihood)。
P(B|A)是已知A发生后B的条件概率,是我们要求的值,叫做后验概率。
P(A|B)/P(A)是调整因子,也被称作标准似然度(standardised likelihood)。
贝叶斯推断中有几个关键的概念需要说明下:
第一个是先验概率,先验概率是指我们主观通过事件发生次数对概率的判断。
第二个是似然函数,似然函数是对某件事发生可能性的判断,与条件概率正好相反。通过事件已经发生的概率推算事件可能性的概率。
维基百科中对似然函数与概率的解释:
概率: 是给定某一参数值,求 某一结果的可能性 。
例如,抛一枚匀质硬币,抛10次,6次正面向上的可能性多大?
似然函数 :给定某一结果,求某一参数值的可能性。
例如,抛一枚硬币,抛10次,结果是6次正面向上,其是匀质的可能性多大?
第三个是调整因子:调整因子是似然函数与先验概率的比值,这个比值相当于一个权重,用来调整后验概率的值,使后验概率更接近真实概率。调整因子有三种情况,大于1,等于1和小于1。
调整因子P(A|B)/P(A)>1:说明事件可能发生的概率要大于事件已经发生次数的概率。
调整因子P(A|B)/P(A)=1:说明事件可能发生的概率与事件已经发生次数的概率相等。
调整因子P(A|B)/P(A)<1:说明事件可能发生的概率与事件小于已经发生次数的概率。
因此,贝叶斯推断可以理解为通过先验概率和调整因子来获得后验概率。其中调整因子是根据事件已经发生的概率推断事件可能发生的概率(通过硬币正面出现的次数来推断硬币均匀的可能性),并与已经发生的先验概率(硬币正面出现的概率)的比值。通过这个比值调整先验概率来获得后验概率。
后验概率 = 先验概率 x 调整因子
代码实践
思路:
1, 准备数据 词汇 和 标签
2,将每一个 单词 用 词袋 模型 表示 我们先用 最简单的表示方式:
比如 一句话中 各种词出现的次数 那么用下面这个向量表示 这个句子。
买房“”, “办理“”,“”贷款“”,“”优惠
1 0 0 1
多句话 就表示成矩阵 。
1001
1101
0011
3, 求解 每一个词 在 正常言论 和 侮辱言论中的概率。
4,预测 用贝叶斯 求解 当来了 一个 新句子 里面 各种词的 出现在
侮辱言论中的概率 和 正常言论 的概率 然后对比。 求解是 不是正常言论。
注意:代码中 对比 是用的 取log 避免了小数点溢出问题。 都取log 对比起来好对比。
#coding=utf-8
from numpy import *
def loadDataSet():
'''
postingList: 进行词条切分后的文档集合
classVec:类别标签
'''
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
def createVocabList(dataSet):
vocabSet = set([])#使用set创建不重复词表库
for document in dataSet:
vocabSet = vocabSet | set(document) #创建两个集合的并集
return list(vocabSet)
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList)#创建一个所包含元素都为0的向量
#遍历文档中的所有单词,如果出现了词汇表中的单词,则将输出的文档向量中的对应值设为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
'''
我们将每个词的出现与否作为一个特征,这可以被描述为词集模型(set-of-words model)。
如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,
这种方法被称为词袋模型(bag-of-words model)。
在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。
为适应词袋模型,需要对函数setOfWords2Vec稍加修改,修改后的函数称为bagOfWords2VecMN
'''
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
def trainNB0(trainMatrix,trainCategory):
'''
朴素贝叶斯分类器训练函数(此处仅处理两类分类问题)
trainMatrix:文档矩阵
trainCategory:每篇文档类别标签
'''
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
#初始化所有词出现数为1,并将分母初始化为2,避免某一个概率值为0
p0Num = ones(numWords); p1Num = ones(numWords)#
p0Denom = 2.0; p1Denom = 2.0 #
'''
稀疏矩阵中 每一个单词 在0 或者1 分类中出现的 概率
'''
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
print("p1Num==",p1Num,p1Denom)
#将结果取自然对数,避免下溢出,即太多,很小的数相乘造成的影响
p1Vect = log(p1Num/p1Denom)#change to log()
p0Vect = log(p0Num/p0Denom)#change to log()
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
'''
分类函数
vec2Classify:要分类的向量
p0Vec, p1Vec, pClass1:分别对应trainNB0计算得到的3个概率
'''
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
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))
print("trainMat==",trainMat)
print("listClasses==",listClasses)
#训练模型,注意此处使用array
p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
print(p0V,p1V)
testEntry = ['love', 'my', 'dalmation']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry = ['stupid', 'garbage']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
print("thisDoc ==",thisDoc)
testingNB()
参考文献
https://www.tuicool.com/articles/F3Ujemi
https://blog.csdn.net/qq_39422642/article/details/78389063