机器学习算法--贝叶斯公式及分类应用、附源代码

机器学习--贝叶斯分类

作者:wangxinxi
贝叶斯分类已经是老生常谈了,应用也很广泛,但是我发现资料有些是偏于理论, 有些是偏于堆积代码, 遂有写此blog的想法,希望能帮助到一部分人。本文难免有错误之处,希望能指出来

1、男女的问题


试想一下,你前往影院看电影,突然发现前面看电影的一个人的门票掉在了地上,,此刻应该是我们发扬中华民族传统美德的是时候了!但是你偏偏只看到了背景,通过看到的背景推断,那么你应该提醒说“Hello,美女,你的电影票掉了"”, 还是应该说:“Hi,帅哥,你的电影票掉了”。很显然,考虑到我们对男人和女人发型的认知,或许会潜意识的认为这位是位女士,那么结果真的是这样的? 让我们量化一下数据后,再做分析。
第一种情况:电影院 100个人中,50个男人,50个女人。50个女人中,25人长发,25人短发。而50个男人中,48人短发,2人长发。存在25个长发女人和2个长发男人,由此推断,门票持有 者为女士的可能性很大。
第二中况情况:稍微变一下,电影院100个人中,98个男人,2个女人。2个女人中,1人长发,1人短发。而98个男人中,94人短发,4人长发。此时 这个人是美女还是帅哥的可能性大一些?很容易计算一共有1个长发女人和4个长发男人,所以此人是男人的可能性更大。
那么问题来了,第一种情况:女人的长发的概率是25/50、男人长发的概率是2/48,第二种情况:女人的长发的概率1/2、男人长发的概率4/98。男人和女人中,长发的概率并没有发生太大的改变, 但是结果却很不一样。透过现象要分析本质原因,影响推断结果不仅仅是男女中长发概率相关,还和男女的所占的比例相关。这么说有什么理论依据?贝叶斯也许可以很好的帮我们解答这个问题。

2、贝叶斯

贝叶斯(Thomas Bayes,1701—1761)英国牧师、“ 业余 ”数学家(其实我也想当业余的)。生活在18世纪的贝叶斯生前是位受人尊敬英格兰长老会牧师。为了证明上帝的存在,他发明了概率统计学原理,遗憾的是,他的这一美好愿望至死也未能实现。贝叶斯在数学方面主要研究概率论。他首先将归纳推理法用于概率论基础理论,并创立了贝叶斯统计理论,对于统计决策函数、统计推断、统计的估算等做出了贡献。1763年发表了这方面的论著,对于现代概率论和数理统计都有很重要的作用,其所采用的许多术语被沿用至今。贝叶斯思想和方法对概率统计的发展产生了深远的影响。今天,贝叶斯思想和方法在许多领域都获得了广泛的应用。


3、贝叶斯公式
贝叶斯定理也称贝叶斯推理,公式表达:
事件A,事件B,则事件A发生在事件B的条件之上的概率:


贝叶斯公式的名词的定义:

其推导过程如下:
如果P(A) > 0、P(B) > 0

解释一下推导过程,首先由条件概率公式可知:

或者

然后由乘法公式,把分母乘到左边可得:

从而可得贝叶斯公式:

或许写成:

多说一句,也有人把贝叶斯写成:


是因为,由全概率公式:
设 B1,B2,....Bn 是样本空间Ω的一个划分,B1,B2....Bn两两互斥,
P(A)=P(AΩ)

证明全概率公式:

然后把条件概率P(AB)=P(A|B)·P(B)带入,即可得全概率公式

把全概率公式带入 贝叶斯公式:


写成这样是因为有时候直接求P(A)比较困难,可以迂回的通过全概率公式求出来P(A)。

在全概率公式中,如果将A看成是“结果”,Bi看成是导致结果发生的诸多“原因”之一,那么全概率公式就是一个“原因推结果”的过程。但贝叶斯公式却恰恰相反。贝叶斯公式中,我们是知道结果A已经发生了,所要做的是反过来研究造成结果发生的原因,是Bi原因造成的可能性有多大,即“结果推原因”。贝叶斯公式体现的是因果的关系,可以通过一些已经知道的信息推测出未知的信息。

4、后知后觉--通过贝叶斯公式来分析男女
我们通过贝叶斯公式来分析上述的背景是长头发的是男还是女的问题。
设:A1为女人的概率,A2为男人的概率;B1为长头发的概况,B2为短头发的概率
第一种情况推断:
长头发的是女的概率P(A1|B1) = P(B1|A1)·P(A1)/P(B1)=(25/50)·(50/100)/((25+2)/100) = 50/54
长头发的是男的概率P(A2|B1) = P(B1|A2)·P(A2)/P(B1)=(2/50)·(50/100)/((25+2)/100) = 4/54
很显然长头发的是美女的概率比较大。
第二种情况的推断:
长头发的是女的概率P(A1|B1) = P(B1|A1)·P(A1)/P(B1)=(1/2)·(2/100)/((1+4)/100) = 1/5
长头发的是男的概率P(A2|B1) = P(B1|A2)·P(A2)/P(B1)=(4/98)·(98/100)/((1+4)/100) = 4/5
很显然长头发的是帅哥的概率比较大。

5、贝叶斯应用--垃圾邮件过滤
现在贝叶斯已经广泛应用了, 海难搜救、生物医药、疾病诊断、邮件过滤、文本分类 、侦破案件、工业生产等很多方面。几个标准事件,1、 联邦党人文集作者公案;2、天蝎号核潜艇搜救等,具体可以参见: 大数据背后的神秘公式(上):贝叶斯公式

下面我们用来介绍一个经典的案例:垃圾邮件过滤。

我们机会每天都会收到类似以下的垃圾邮件:
“XX公司优惠,商品打折,全场八折,返利多少钱”
“金融公司,XX理财产品,XX保险”
“招聘兼职,工资日结”
诸如此类的垃圾邮件,铺天盖地、没完没了的发。我们能不能通过一个算法自动的识别出这些垃圾邮件呢?贝叶斯公式就很好用, 下面我们来一步步的讲如果利用贝叶斯公式解决垃圾邮件。
1、进行中文分词
例如把“ 晚上在公司聚餐 ”,进行中文分词会变成:“晚上/ 在/ 公司/ 聚餐”四个单词。常用的中文分词库有jieba等分词工具。
2、分词后去掉停用词
汉语去掉一些“是、在”等之类停用词之后,并不能明显影响句子表达的信息,反而能提高计算速度和准确率。比如“晚上在公司聚餐 ”把“在”去掉之后对句子的影响就有限。常用的停用词也有字典
3、构建词向量
把所有的词语聚起来并去重,形成一个全部的词的集合。然后,根据单词是否出现在每个里面,构建每个邮件的词向量。
4、计算分类概率
根据贝叶斯公式


设B1为垃圾邮件,B2为正常邮件; A为待分类的邮件, 按照贝叶斯算法我们需要求出邮件A为垃圾邮件的概率P(B1|A) 和为正常邮件的概率P(B2|A),二分类里面最大的概率作为推测的分类。

然而,事情往往没有这么容易, 邮件A可能在我们的已知分类库没有出现过,所以很难求出P(A|B1)和P(A|B2)。事情进行到这里仿佛陷入了僵局。。。。让我们在梳理一下思绪,我们刚刚把邮件通过分词都向量化了,邮件A可以表示为一个[w0,w1,w2,w3....wn]的特征, 就是说事件A是由若干个特征表示, 如果特征彼此独立而都有相等的重要性 ,那么P(A|B1)= P(w0|B1)·P(w1|B1)·P(w2|B1)·....P(wn|B1),而P(w0|B1)、P(w1|B1)、P(w2|B1)·....P(wn|B1)的每一项都可以通过已知的条件计算出来。这就是传说的 朴素贝叶斯分类器(Naive Bayes classifiers) ,naive的英文意思是“幼稚的; 天真的; 单纯的”。我们把汉语中每个单词出现想象成“独立的和同等重要的”,这件事情确实够“天真的”,但是当我们天真一回后,通过结果你会发现这种“天真”反而很有用。

再来回顾公式

我们会发现分母都有P(A), 所以我只需要比较P(A|B)·P(B),求出最大的P(A|B)·P(B)就可以认为是我们预测出来的分类。
环境:Python3
库:numpy
分词后,下面是简单实现的代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @time : 2018/3/13 22:01
# @author : wangxinxi
# @file : bayes.py
# @aoftware: PyCharm

from numpy import *
from functools import reduce

#广告、垃圾标识
adClass = 1

def loadDataSet () :
'''加载数据集合及其对应的分类'''
wordsList = [[ '周六' , '公司' , '一起' , '聚餐' , '时间' ] ,
[ '优惠' , '返利' , '打折' , '优惠' , '金融' , '理财' ] ,
[ '喜欢' , '机器学习' , '一起' , '研究' , '欢迎' , '贝叶斯' , '算法' , '公式' ] ,
[ '公司' , '发票' , '税点' , '优惠' , '增值税' , '打折' ] ,
[ '北京' , '今天' , '雾霾' , '不宜' , '外出' , '时间' , '在家' , '讨论' , '学习' ] ,
[ '招聘' , '兼职' , '日薪' , '保险' , '返利' ]]
# 1 是, 0 否
classVec = [ 0 , 1 , 0 , 1 , 0 , 1 ]
return wordsList , classVec


def doc2VecList (docList) :
'''合并去重,生成包含所有单词的集合'''
return list (reduce( lambda x , y : set (x) | set (y) , docList))


def words2Vec (vecList , inputWords) :
'''把单子转化为词向量'''
resultVec = [ 0 ] * len(vecList)
for word in inputWords :
if word in vecList :
# 在单词出现的位置上的计数加1
resultVec[vecList.index(word)] += 1
else :
print ( '没有发现此单词' )
return array(resultVec)


def trainNB (trainMatrix , trainClass) :
'''计算,生成每个词对于类别上的概率'''
numTrainClass = len(trainClass)
numWords = len(trainMatrix[ 0 ])
# 全部都初始化为1, 防止出现概率为0的情况出现
p0Num = ones(numWords)
p1Num = ones(numWords)
# 相应的单词初始化为2
p0Words = 2.0
p1Words = 2.0
# 统计每个分类的词的总数
for i in range (numTrainClass) :
if trainClass[i] == 1 :
#数组在对应的位置上相加
p1Num += trainMatrix[i]
p1Words += sum(trainMatrix[i])
else :
p0Num += trainMatrix[i]
p0Words += sum(trainMatrix[i])
# 计算每种类型里面, 每个单词出现的概率
p0Vec = log(p0Num / p0Words)
p1Vec = log(p1Num / p1Words)
# 计算1出现的概率
pClass1 = sum(trainClass) / float (numTrainClass)
return p0Vec , p1Vec , pClass1


def classifyNB (testVec , p0Vec , p1Vec , pClass1) :
'''朴素贝叶斯分类, max(p0, p1)作为推断的分类'''
# y=x 是单调递增的, y=ln(x)也是单调递增的。 , 如果x1 > x2, 那么ln(x1) > ln(x2)
# 因为概率的值太小了,所以我们可以取ln, 根据对数特性ln(ab) = lna + lnb, 可以简化计算
# sum是numpy的函数
p1 = sum(testVec * p1Vec) + log(pClass1)
p0 = sum(testVec * p0Vec) + log( 1 - pClass1)
if p0 > p1 :
return 0
return 1

def printClass (words , testClass):
if testClass == adClass:
print (words , '推测为:广告邮件' )
else :
print (words , '推测为:正常邮件' )

def tNB () :
'''测试,进行预测'''
docList , classVec = loadDataSet()
# 生成包含所有单词的list
allWordsVec = doc2VecList(docList)
# 构建词向量矩阵
trainMat = list ( map ( lambda x : words2Vec(allWordsVec , x) , docList))
# 训练计算每个词在分类上的概率, p0V:每个单词在非分类出现的概率, p1V:每个单词在是分类出现的概率
p0V , p1V , pClass1 = trainNB(trainMat , classVec)
testWords = [ '公司' , '聚餐' , '讨论' , '贝叶斯' ]
# 当前需要预测的词向量
testVec = words2Vec(allWordsVec , testWords)
# 预测分类
testClass = classifyNB(testVec , p0V , p1V , pClass1)
printClass(testWords , testClass)
# 预测
testWords = [ '公司' , '保险' , '金融' ]
testVec = words2Vec(allWordsVec , testWords)
testClass = classifyNB(testVec , p0V , p1V , pClass1)
printClass(testWords , testClass)


if __name__ == '__main__' :
tNB()


代码执行结果:
['公司', '聚餐', '讨论', '贝叶斯'] 推测为:正常邮件
['公司', '保险', '金融'] 推测为:广告邮件

代码已经上传至github上: https://github.com/qiuyukuhe/ml

朴素贝叶斯算法局限性:如果特征变量的有些特征关联性较强(比如“首都”“北京”这两个词就很大的可能同时出现),或者特征之间的重要性不一样(比如,TF-IDF(词频和逆词频)的问题), 在解决比较复杂的问题的时候效果就不是那么好。

邮件过滤攻防:现在很多垃圾邮件通过发送图片、链接等途径来避过贝叶斯分类算法。

您可以随意转载、修改此文章

参考:
《机器学习实战》


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值