朴素贝叶斯算法

简介

贝叶斯学派很古老,但是从诞生到一百年前一直不是主流。主流是频率主义学派。频率主义学派的权威皮尔逊和费歇尔都对贝叶斯学派不屑一顾,但是贝叶斯学派硬是凭借在现代特定领域的出色应用表现为自己赢得了半壁江山。

贝叶斯学派的思想可以概括为先验概率+数据=后验概率。也就是说我们在实际问题中需要得到的后验概率,可以通过先验概率和数据一起综合得到。数据大家好理解,被频率学派攻击的是先验概率,一般来说先验概率就是我们对于数据所在领域的历史经验,但是这个经验常常难以量化或者模型化,于是贝叶斯学派大胆的假设先验分布的模型,比如正态分布,beta分布等。这个假设一般没有特定的依据,因此一直被频率学派认为很荒谬。虽然难以从严密的数学逻辑里推出贝叶斯学派的逻辑,但是在很多实际应用中,贝叶斯理论很好用,比如垃圾邮件分类,文本分类。

贝叶斯决策论

贝叶斯决策论(Bayesian decision theory)是概率框架下实施决策的基本方法。对分类任务来说,在所有相关概率都已知的理想情形下,贝叶斯决策论考虑如何基于这些概率和误判损失来选择最优的类别标记。

具体来说,若我们决策的目标是最小化分类错误率,贝叶斯最优分类器要对每个样本 x,选择能使后验概率 P( c | x )最大的类别 c 标记。在现实任务中后验概率通常难以直接获得。从这个角度来说,机器学习所要实现的是基于有限的训练样本集尽可能准确地估计出后验概率 P( c | x )。大体来说,主要有两种策略:给定x,可通过直接建模P( c | x )来预测c,这样得到的是“判别式模型”,例如,决策树、BP神经网络、支持向量机等等;也可先对联合概率分布P( x,c )建模,然后在由此获得P( c | x ),这样得到的是“生成式模型”。对于生成式模型来说,必然考虑

基于贝叶斯定理, P( c | x )可写为

这就将求后验概率P(c|x)的问题转变为求类先验概率P(c)和条件概率P(x|c)。

类先验概率 P(c) 表达了样本空间中各类样本所占的比例,根据大数定律,当训练集包含充足的独立同分布样本时,P(c) 可通过各类样本出现的频率来进行估计。

因为对于类条件概率 P( x | c ) 来说,由于它涉及关于 x 所有属性的联合概率,直接根据样本出现的频率来估计将会遇到严重的困难。假如样本的d个属性都是二值的,则样本空间将有2的d次方种可能取值,在现实中,这个种类数往往大于训练样本,也就是说,很多样本取值在训练集中根本没有出现,直接使用频率来估计 P( x | c )显然不可行,因为“未被观测到”与“出现概率为零”通常是不同的。这可以通过极大似然估计来解决。

朴素贝叶斯分类器

基于贝叶斯公式来估计后验概率P( c | x )的主要困难在于:类条件概率P( x | c )是所有属性上的联合概率,难以从有限的训练样本直接估计而得。因此朴素贝叶斯分类器采用了“属性条件独立性假设”:对已知类别,假设所有属性相互独立。也就是说,假设每个属性独立的对分类结果发生影响。

基于属性独立性假设,后验概率P( c | x )可写为

显然朴素贝叶斯分类器的训练过程就是基于训练集D来估计类先验概率P( c ),并为每个属性估计条件概率P( x|c )。

由于对所有类别来说P( x )相同,因此贝叶斯判定准则有

下面是一个用西瓜数据集3.0训练朴素贝叶斯分类器,对测试例“测1”进行分类:



注意:实践中常通过取对数的方式来将“连乘”转化为“连加”以避免数值下溢。

拉普拉斯修正

若某个属性值在训练集中没有与某个类同时出现过,则基于式(7.17)进行概率估计,再根据式(7.15)进行判别将出现问题。例如在使用西瓜数据集3.0训练朴素贝叶斯分类器时,对一个“敲声=清脆”的测试例,有

由于式(7.15)的连乘式计算出的概率值为零,因此,无论该样本的属性如何,分类的结果都是“好瓜=否”,这明显不合理。

这时候就要进行“平滑”,常用“拉普拉斯修正”。式(7.16)和(7.17)分别修正为

显然,拉普拉斯修正避免了因训练集不充分而导致概率估值为零的问题,并且在训练集变大时,修正过程所引入的先验的影响也会逐渐变得可忽略,使得估值渐趋向于实际概率值。

朴素贝叶斯的实现代码

引入了拉普拉斯修正,数据集用的是西瓜数据集3.0


西瓜数据集3.0
import numpy as np
import pandas as pd

dataset = pd.read_csv('watermelon_3.csv', delimiter=",")
del dataset['编号']
print(dataset)
X = dataset.values[:, :-1]
m, n = np.shape(X)
for i in range(m):
    X[i, n - 1] = round(X[i, n - 1], 3)
    X[i, n - 2] = round(X[i, n - 2], 3)
y = dataset.values[:, -1]
columnName = dataset.columns
colIndex = {}
for i in range(len(columnName)):
    colIndex[columnName[i]] = i

Pmap = {}  # 函数P很耗时间,而且经常会求一样的东西,因此我加了个记忆化搜索,用map存一下,避免重复计算
kindsOfAttribute = {}  # kindsOfAttribute[0] = 3,因为有3种不同的类型的"色泽"
for i in range(n):
    kindsOfAttribute[i] = len(set(X[:, i]))
continuousPara = {}  # 记忆一些参数的连续数据,以避免重复计算

goodList = []
badList = []
for i in range(len(y)):
    if y[i] == '是':
        goodList.append(i)
    else:
        badList.append(i)

import math


def P(colID, attribute, C):  # P(colName=attribute|C) P(色泽=青绿|是)
    if (colID, attribute, C) in Pmap:
        return Pmap[(colID, attribute, C)]
    curJudgeList = []
    if C == '是':
        curJudgeList = goodList
    else:
        curJudgeList = badList
    ans = 0
    if colID >= 6:
        mean = 1
        std = 1
        if (colID, C) in continuousPara:
            curPara = continuousPara[(colID, C)]
            mean = curPara[0]
            std = curPara[1]
        else:
            curData = X[curJudgeList, colID]
            mean = curData.mean()
            std = curData.std()
            # print(mean,std)
            continuousPara[(colID, C)] = (mean, std)
        ans = 1 / (math.sqrt(math.pi * 2) * std) * math.exp((-(attribute - mean) ** 2) / (2 * std * std))
    else:
        for i in curJudgeList:
            if X[i, colID] == attribute:
                ans += 1
        ans = (ans + 1) / (len(curJudgeList) + kindsOfAttribute[colID])
    Pmap[(colID, attribute, C)] = ans
    # print(ans)
    return ans


def predictOne(single):
    ansYes = math.log2((len(goodList) + 1) / (len(y) + 2))  
    ansNo = math.log2((len(badList) + 1) / (len(y) + 2))
    for i in range(len(single)):  # 书上是连乘,但在实践中要把“连乘”通过取对数的方式转化为“连加”以避免数值下溢
        ansYes += math.log2(P(i, single[i], '是'))
        ansNo += math.log2(P(i, single[i], '否'))
    # print(ansYes,ansNo,math.pow(2,ansYes),math.pow(2,ansNo))
    if ansYes > ansNo:
        return '是'
    else:
        return '否'


def predictAll(iX):
    predictY = []
    for i in range(m):
        predictY.append(predictOne(iX[i]))
    return predictY


predictY = predictAll(X)
print(y)
print(np.array(predictAll(X)))

confusionMatrix = np.zeros((2, 2))
for i in range(len(y)):
    if predictY[i] == y[i]:
        if y[i] == '否':
            confusionMatrix[0, 0] += 1
        else:
            confusionMatrix[1, 1] += 1
    else:
        if y[i] == '否':
            confusionMatrix[0, 1] += 1
        else:
            confusionMatrix[1, 0] += 1
print(confusionMatrix)

输出结果

输出结果说明:

[7,2]表示预测的结果有7个坏瓜预测成功,两个预测成好瓜
[1,7]表示预测的结果有一个好瓜预测成坏瓜,7个好瓜预测成好瓜

代码以及数据集可以到我码云下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,928评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,748评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,282评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,065评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,101评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,855评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,521评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,414评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,931评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,053评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,191评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,873评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,529评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,074评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,188评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,491评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,173评论 2 357

推荐阅读更多精彩内容

  • 在所有的机器学习分类算法中,朴素贝叶斯和其他绝大多数的分类算法都不同。对于大多数的分类算法,比如决策树,KNN,逻...
    云时之间阅读 1,896评论 6 24
  • 忘光了概率统计的知识还想学朴素贝叶斯算法?这一篇就是为你准备的。虽然如此,作为初学者,别指望 5 分钟就能完全理解...
    kamidox阅读 2,697评论 4 7
  • 贝叶斯简介 贝叶斯定理是一个特别简单但是特别有用的定理,这个定理解决了生活中经常遇到的一个问题:在已知P(A|B)...
    Jlan阅读 761评论 0 1
  • 很久前去过一次上川岛,只依稀记得那里的海水特别蓝,很干净,浪不大,穿上救生衣自在地浮在海面的感觉很惬意。于是...
    _荷包蛋_阅读 841评论 0 1
  • 提到全职妈妈,很多人的膝跳反应是“那不是整天没事干,围着孩子转吗?”一句话道出了全职妈妈的两大困境和烦恼:1.缺少...
    莹莹_阅读 417评论 0 6