李航统计方法(四)---朴素贝叶斯

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。训练的时候,学习输入输出的联合概率分布;分类的时候,利用贝叶斯定理计算后验概率最大的输出。

朴素贝叶斯法的学习与分类

基本方法

设输入空间
image

为n维向量的集合,输出空间为类标记集合
image

={c1……ck}。输入特征向量x和输出类标记y分属于这两个集合。X是输入空间上的随机变量,Y是输出空间上的随机变量。P(X,Y)是X和Y的联合概率分布,训练数据集

image

由P(X,Y)独立同分布产生。

朴素贝叶斯法通过T学习联合概率分布P(X,Y)。具体来讲,学习以下先验概率:


image.png

以及条件概率分布:


image.png

于是根据联合概率分布密度函数:


image.png

学习到联合概率分布P(X,Y)。

而条件概率分布
image

的参数数量是指数级的,也就是X和Y的组合很多,假设xj可能取值Sj个,Y可能取值有K个,那么参数的个数是

image

。特别地,取xj=S,那么参数个数为KSn,当维数n很大的时候,就会发生维数灾难。

豆知识:维数灾难

一维空间中,把一个单位空间(退化为区间)以每个点距离不超过0.01采样,需要102个平均分布的采样点,而在10维度空间中,需要1020个点才行。计算方式用Python描述如下:

    dimensionality = 10
    print 1 / (0.01 ** dimensionality)
    也可以如下可视化:

    # -*- coding:utf-8 -*-
    # Filename: dimensionality.py
    # Author:hankcs
    # Date: 2015/2/6 14:40
    from matplotlib import pyplot as plt
    import numpy as np
     
    max_dimensionality = 10
    ax = plt.axes(xlim=(0, max_dimensionality), ylim=(0, 1 / (0.01 ** max_dimensionality)))
    x = np.linspace(0, max_dimensionality, 1000)
    y = 1 / (0.01 ** x)
    plt.plot(x, y, lw=2)
    plt.show()

可视化图像:


image.png

这种指数级的复杂度增长被称为维数灾难。

看完这个图大概就能理解为什么条件概率分布
image

无法计算了。

为了计算它,朴素贝叶斯法对它做了条件独立性的假设:


image.png

也就是各个维度的特征在类确定的情况下都是独立分布的。这一假设简化了计算,也牺牲了一定的分类准确率。

基于此假设,以及贝叶斯定理,后验概率为:

image.png

分母其实是P(X=x),等同于枚举ck求联合分布的和:∑P(X=x,Y=ck),此联合分布按公式
image

拆开,等于上式分母。

将独立性假设代入上式,得到


image.png

朴素贝叶斯分类器可以表示为:

image

也就是给定参数,找一个概率最大的ck出来。注意到上式分母其实就是P(X=x),x给定了就固定了,跟ck一点关系都没有,所以分母可以去掉,得到:

image.png

也就是给定参数,找一个概率最大的ck出来。注意到上式分母其实就是P(X=x),x给定了就固定了,跟ck一点关系都没有,所以分母可以去掉,得到:

image

后验概率最大化的含义

选择0-1损失函数:


image.png

f(X)就是分类器的决策函数,损失函数的参数其实是一个联合分布。

此时期望风险函数为:

image

上面说过,这是一个联合分布P(X,Y),是一个and(连乘)的形式,由此取条件期望为风险函数:

image

所谓条件期望,就是指X=x时,Y的期望。上式其实可以这么推回去:

Ex∑[L()]P(ck|X)=∑P(X)∑[L()]P(X,ck)/P(X)=∑[L()]P(X,ck)=E[L()]

格式比较乱,但愿意思到了。

为了最小化上式,只需对每个X=x执行最小化,那么加起来肯定是极小化的,由此有:


image.png

其实不用这么一堆公式,光靠感觉也很好理解,给了一些证据后,不挑后验概率最大的,还能挑啥呢?

朴素贝叶斯法的参数估计

极大似然估计

前面说过,朴素贝叶斯法要学习的东西就是P(Y=ck)和P(X=x|Y=ck),这两个概率的估计用极大似然估计法(简单讲,就是用样本猜测模型参数,或者说使得似然函数最大的参数)进行:

image

也就是用样本中ck的出现次数除以样本容量。

image

分子是样本中变量组合的出现次数,分母是上面说过的样本中ck的出现次数。

学习与分类算法

于是就有朴素贝叶斯算法,先从训练数据中计算先验概率和条件概率,然后对于给定的实例计算最大的条件概率,输出该条件对应的类别。形式化的描述如下:

image

例子

给定训练数据:

image.png

给x=(2,S)T分类。

这个太简单了,利用(3)中的式子就行了。

贝叶斯估计

最大似然估计有个隐患,假设训练数据中没有出现某种参数和类别的组合怎么办?此时估计的概率值为0,但是这不代表真实数据中就没有这样的组合。解决办法是采用贝叶斯估计

1、条件概率的贝叶斯估计:

image

其中
image

,Sj表示xj可能取值的种数。分子和分母分别比最大似然估计多了一点东西,其意义是在随机变量每个取值的频数上加一个常量

image

。当此常量取0时,就是最大似然估计,当此常量取1时,称为拉普拉斯平滑。

2、先验概率的贝叶斯估计:

image

贝叶斯情感极性分析器

书中例题太简单,不过瘾。这里分析一个基于贝叶斯文本分类器实现的简单情感极性分析器。

调用实例:
# -- coding:utf-8 --
# Filename: Bayes.py
# Author:hankcs
# Date: 2015/2/6 22:25
from math import log, exp

    class LaplaceEstimate(object):
        """
        拉普拉斯平滑处理的贝叶斯估计
        """
     
        def __init__(self):
            self.d = {}  # [词-词频]的map
            self.total = 0.0  # 全部词的词频
            self.none = 1  # 当一个词不存在的时候,它的词频(等于0+1)
     
        def exists(self, key):
            return key in self.d
     
        def getsum(self):
            return self.total
     
        def get(self, key):
            if not self.exists(key):
                return False, self.none
            return True, self.d[key]
     
        def getprob(self, key):
            """
            估计先验概率
            :param key: 词
            :return: 概率
            """
            return float(self.get(key)[1]) / self.total
     
        def samples(self):
            """
            获取全部样本
            :return:
            """
            return self.d.keys()
     
        def add(self, key, value):
            self.total += value
            if not self.exists(key):
                self.d[key] = 1
                self.total += 1
            self.d[key] += value
     
     
    class Bayes(object):
        def __init__(self):
            self.d = {}  # [标签, 概率] map
            self.total = 0  # 全部词频
     
     
        def train(self, data):
            for d in data:  # d是[[词链表], 标签]
                c = d[1]  # c是分类
                if c not in self.d:
                    self.d[c] = LaplaceEstimate()  # d[c]是概率统计工具
                for word in d[0]:
                    self.d[c].add(word, 1)  # 统计词频
            self.total = sum(map(lambda x: self.d[x].getsum(), self.d.keys()))
     
        def classify(self, x):
            tmp = {}
            for c in self.d:  # 分类
                tmp[c] = log(self.d[c].getsum()) - log(self.total)  # P(Y=ck)
                for word in x:
                    tmp[c] += log(self.d[c].getprob(word))          # P(Xj=xj | Y=ck)
            ret, prob = 0, 0
            for c in self.d:
                now = 0
                try:
                    for otherc in self.d:
                        now += exp(tmp[otherc] - tmp[c])            # 将对数还原为1/p
                    now = 1 / now
                except OverflowError:
                    now = 0
                if now > prob:
                    ret, prob = c, now
            return (ret, prob)
     
     
    class Sentiment(object):
        def __init__(self):
            self.classifier = Bayes()
     
        def segment(self, sent):
            words = sent.split(' ')
            return words
     
        def train(self, neg_docs, pos_docs):
            data = []
            for sent in neg_docs:
                data.append([self.segment(sent), u'neg'])
            for sent in pos_docs:
                data.append([self.segment(sent), u'pos'])
            self.classifier.train(data)
     
        def classify(self, sent):
     
            return self.classifier.classify(self.segment(sent))
     
    s = Sentiment()
    s.train([u'糟糕', u'好 差劲'], [u'优秀', u'很 好']) # 空格分词
     
    print s.classify(u"好 优秀")

输出
(u'pos', 0.6666666666666665)

说明“好优秀”这句话具有正能量的概率是66%,虽然“好”这个词语也存在于负极性的语句中,但是分类器还是准确地区分了它。

上面的贝叶斯分类器使用了拉布拉斯平滑处理策略,在进行条件概率的时候,不是连乘,而是取对数相加,最后逐差取指数,这个过程会发生归一化,得出一个概率出来。

Reference

情感极性分析器主要参考了snownlp的实现。

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

推荐阅读更多精彩内容