机器学习之朴素贝叶斯分类器

继续我们的学习,今天我们记录的是朴素贝叶斯分类器

什么是朴素贝叶斯

学过概率论的同学应该知道贝叶斯公式,就是那个全概率公式的逆形式,通过前验概率来求后验概率。


贝叶斯公式

我们这里只简单的理解一下贝叶斯公式,因为这些基础内容不是我们这篇文章重点介绍的内容

相比全概率公式是知道原因求结果概率,
贝叶斯公式是已知结果来求得原因概率

这是我们概率老师当时讲的。

什么是朴素贝叶斯?朴素贝叶斯怎么分类?

举个例子:

例子:
现在我们有5个训练数据(2维特征向量),X = {x1, x2, x3, x4, x5},这五个数据分别属于两个类型Y,Y = {y1, y2}
现在,我随便给你一个特征向量Xr,问你他属于那个类别?
实际上,这个问题可以转化为这样的一个问题:

比较属于那种类别的概率更大

那么前面我们用到的贝叶斯公式就排上了用场:
贝叶斯公式

根据贝叶斯公式以及链式法则,我们得到了这个公式,但是我们需要注意,这仅仅是二维的特征空间,就已经很难算了,如果维度达到三十维呢?

所以,朴素贝叶斯就被提出来了,其实朴素贝叶斯的naive不应该翻译为朴素,还应该是“天真”(个人看法),为什么这么说呢?我们接着看这个例子:
因为上面的式子很难算,于是在20世纪50年代有人提出了这个假设(from wiki):

特征向量的各个特征独立同分布

这意味着什么?


朴素贝叶斯

这样就好算了很多,这个假设会使我们的分类模型损失一些精度,但是却降低了特别多的计算难度。


接着,我们继续计算这个条件概率:
首先,我们看分母,这是一个常数,对于比较概率大小没有影响,所以将他忽略(不信可以全概率公式展开)。
然后,我们需要计算的就是:
p(y)先验概率以及两个条件概率,可能悟性好的朋友就已经知道了,这个可以通过训练数据中的频率来估计概率,这是没错的。
但是,这只有在数据样本特别大的时候,才能这样。那我们怎么做呢?

极大似然估计

这也是概率论里面的参数估计的方法,首先,我们先来理解一下什么是似然:

“似然性”与“或然性”或“概率”意思相近,都是指某种事件发生的可能性,但是在统计学中,“似然性”和“概率”(或然性)又有明确的区分。概率用于在已知一些参数的情况下,预测接下来的观测所得到的结果,而似然性则是用于在已知某些观测所得到的结果时,对有关事物的性质的参数进行估计。在这种意义上,似然函数可以理解为条件概率的逆反。在已知某个参数B时,事件A会发生的概率写作:

似然

摘自wiki
我个人感觉:
这个似然函数的引入有些许tricky的味道,我现在对于他有两种解释:
1、频率学派认为世界是确定的,有一个本体,这个本体的真值是不变的,我们的目标就是要找到这个真值或真值所在的范围;所以对于一个未知的对象,我们要做的就是将他参数化,于是就将条件概率转化为符合某种分布的联合密度函数,我们要做的就是求解参数theta。
2、我们就是假设数据符合某种分布,就像中心极限定理说的一样。然后这组数据的联合条件密度分布就一定可以参数化,所以,我们就引入了极大似然的方法来估计参数值。
以上为个人看法,欢迎大家与我讨论。

极大后验估计

前面说到了频率学派,当然不可避免的就得说到贝叶斯学派,极大后验估计(MAP)是贝叶斯学派的参数估计方法。
在这里就不展开说了,如果想要深入了解,给大家推荐一篇文章,
这里

tricky

我想说一下,我在学习朴素贝叶斯过程中遇到的一些,感觉很tricky的地方。
我们先了解一下,极大似然估计的过程是什么样的:
1、首先,假设数据成某一种分布,如果不确定可以根据中心极限定理,假设他为高斯分布。
2、然后,写出他的似然函数,对于离散量,似然函数就是联合分布函数,对于连续变量,似然函数就是联合密度函数,然后根据不同的分布形式,会有不同的参数。
3、然后进行NLL优化,其实就是用对数函数将累乘变为累加,然后对参数求偏导等于零,然后就算出了参数值

但是我们再看一些文章时,包括sklearn的源码,我们都可以发现一个地方,与我们所说的步骤不同,就是,他们都是直接算出了训练数据集的均值以及方差,直接带到了似然函数中,然后就直接比较了,得到了类别。

开始我十分纳闷,为什么可以这样?这和我们认知的不一样,直到我动手推导了一下这个过程:

符合高斯分布的似然函数

NLL优化

注:这里使用e为底,是为了消去式子里的e方便计算,用2为底一样
对mu求偏导等于零

我们可以发现,解得:mu就等于均值

对sigma求偏导等于零

很明显,结果就是训练数据集的方差

正是这样,我们才可以将均值方差直接带进去。
p(y)也是一个道理。

代码实现:

import numpy as np
import math


class NaiveBayes:
    """
    a step to archieve my dream
    """
    def __init__(self, data_dim, data_num, class_num = 2):
        super(NaiveBayes, self).__init__()
        self.data_dim = data_dim
        self.data_num = data_num
        self.class_num = class_num
        self.data = self.data_make(data_dim, data_num)
        self.mean = np.zeros((class_num, data_dim)).reshape((class_num, data_dim))
        self.var = np.zeros((class_num, data_dim)).reshape((class_num, data_dim))
        self.p_y1 = 0
        self.p_y2 = 0

    def data_make(self, data_dim, data_num):
        """
        make train data
        :param data_dim: dimension of the feature
        :param data_num: the number of train data
        :return: a list of data whose type is dict
        """
        train_data = []
        for _ in range(data_num):

            tmp_data = {}
            tmp_data["data"] = np.random.randn(1, data_dim)
            if _ % 2 == 0:
                flag = -1
            else:
                flag = 1
            tmp_data["flag"] = flag

            train_data.append(tmp_data)
        return train_data

    def fit(self):
        """
        calculate the mean and var of the data
        :return: NULL
        """
        data_list_1 = [data["data"] for data in self.data if data["flag"] == 1]
        data_list_2 = [data["data"] for data in self.data if data["flag"] == -1]
        self.p_y1 = len(data_list_1)/self.data_num
        self.p_y2 = len(data_list_2)/self.data_num
        self.mean[0] = np.mean(data_list_1, axis=0, keepdims=True).reshape(self.data_dim)
        self.mean[1] = np.mean(data_list_2, axis=0, keepdims=True).reshape(self.data_dim)
        self.var[0] = np.std(data_list_1, axis=0, keepdims=True, ddof=1).reshape(self.data_dim)
        self.var[1] = np.std(data_list_1, axis=0, keepdims=True, ddof=1).reshape(self.data_dim)

    def predict(self, data):
        """
        to classify the data
        :param data: the data u wanna classify
        :return: int
        """
        p1 = (1/(pow(2*math.pi, 0.5)*self.var[0][0]))*pow(math.e, -(pow((data[0] - self.mean[0][0]), 2)/2*pow(self.var[0][0], 2)))*(1/(pow(2*math.pi, 0.5)*self.var[0][1]))*pow(math.e, -(pow((data[1] - self.mean[0][1]), 2)/2*pow(self.var[0][1], 2)))
        p2 = (1/(pow(2*math.pi, 0.5)*self.var[1][0]))*pow(math.e, -(pow((data[0] - self.mean[1][0]), 2)/2*pow(self.var[1][0], 2)))*(1/(pow(2*math.pi, 0.5)*self.var[1][1]))*pow(math.e, -(pow((data[1] - self.mean[1][1]), 2)/2*pow(self.var[1][1], 2)))


        print(p1,',',p2)

        if p2 > p1:
            print("[*]: the data belongs to the second class")
        else:
            print("[*]: the data belongs to the first class")

加油

更新

在与小伙伴讨论完这块的内容后,我对于极大似然估计有了新的理解,现在记录一下:
前面我们说了似然概率既有相同之处,又有不同的地方,但具体表现在什么地方呢?

我们得从似然是什么重新说起:
我们先看一个例子:
我们现在抛一个瓶盖,有正反两种情况,但是由于瓶盖密度不均匀,所以我们不知道正面的概率是多少,所以在这里我们假设正面的概率为theta,那么问题来了:
现在我抛了五次,出现了三次正面,两次反面。所以,我问大家theta估计是多少?
那么,现在我们没有别的办法了,所以这里就用到了参数估计的方法:频率学派的最大似然估计法。
似然就是一个事情发生的可能性,但是却不同于概率,概率是告知的theta,但似然是不知道theta,要通过采样来估计theta。
那么对于这个问题的似然函数是什么呢?


似然函数

在开始学习的时候,我有一个误区,就是极大似然估计的似然函数必须是概率密度函数的乘积,正因为这个认识,让我不知道似然函数的实际意义,所以理解不了为啥在这个特定的情景下要引入这个似然函数,但是实际上似然函数是什么呢?
似然其实就是特定事件发生的可能性,只不过我们假设他符合某种分布,然后将概率参数化,也就是化为与theta有关的函数,一个特定的theta对应一个事情发生的概率,就比如说上面的抛瓶盖,根据采样三正一反的样本已经出现,所以我们要通过修正theta值来让他的似然最大化,所以真正的,最正统的似然函数应该是概率公式,也就是上面的那个公式,但是为什么有的时候,我们看到的似然函数是联合密度函数的形式呢?
是因为:在数学上可以证明,概率密度函数的乘积与概率的乘积是有相关性的,而我们的任务是求出使似然函数最大时的theta值,所以概率密度函数也可以用来表示似然函数。

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

推荐阅读更多精彩内容