朴素贝叶斯分类器笔记-Python实现

2020-05-20  本文已影响0人  不想放开的骆驼

前言:

上篇笔记介绍了贝叶斯原理,写这篇笔记,算是承上启下,更深入的学习下贝叶斯原理并应用它。同样,我用Python实现了一个简单的预估「嫁不嫁」的问题的分类器,帮助理解朴素贝叶斯。

朴素贝叶斯介绍:

朴素贝叶斯基于贝叶斯公式,“朴素”是因为「假设各特征之间相互独立」,这一假设使朴素贝叶斯算法变得简单,也牺牲了一定的分类准确性。

优点:

算法简单、分类过程时空开销少

缺点:

「朴素」的假设牺牲了一定的分类准确性

贝叶斯公式:

image

换成分类任务的表达式:

image

则朴素贝叶斯公式:

image

(图片来自网络)

案例:

首先,数据如下:

image

(图片来自网络)

现在给我们的问题是,如果一对男女朋友,男生想女生求婚,男生的四个特点分别是不帅,性格不好,身高矮,不上进,请你判断一下女生是嫁还是不嫁?

根据朴素贝叶斯公式,我们转化为这样的公式:

image

展开后的公式,可以看到,分子和分母有一定的重叠内容,所以我们只需要算

P(嫁)×P(不帅、性格不好、矮、不上进|嫁)

P(不嫁)P(不帅|不嫁)P(性格不好|不嫁)P(矮|不嫁)P(不上进|不嫁)

即可

P(嫁)=P(不嫁)= 1/2 (我这里有点疑惑,P(嫁)是先验概率,我是取所有样本种「嫁」所占比例为先验概率,不知正确与否)

P(性格不好|嫁)=1/6、
P(矮|嫁)=1/6、
P(不上进|嫁)=1/6、
P(不嫁)=1/2、P(不帅|不嫁)=1/3、
P(性格不好|不嫁)=1/2、
P(矮|不嫁)=1、
P(不上进|不嫁)=2/3

代入上边展开了的公式:

P(嫁)P(不帅|嫁)P(性格不好|嫁)P(矮|嫁)P(不上进|嫁)=1/2 * 1/2 * 1/6 * 1/6 * 1/6=1/864

P(不嫁)P(不帅|不嫁)P(性格不好|不嫁)P(矮|不嫁)P(不上进|不嫁)=1/2 * 1/3 * 1/2 * 1* 2/3=1/18

得出:

P(嫁|不帅、性格不好、矮、不上进)=(1/864) / (1/864+1/18)=1/49=2.04%

P(不嫁|不帅、性格不好、矮、不上进) = 1 - P(嫁|不帅、性格不好、矮、不上进)=
97.96%

Python代码:

class naive_bayes(object):
    """naive_bayes demo"""
    def __init__(self, data):
        super(naive_bayes, self).__init__()
        self.data = data
        self.sample_size = len(self.data)
        self.marry = 0 # 样本中,嫁的计数
        self.yes_or_not = 1 # 是否嫁,默认为嫁
        self.counter_marry = [0,0,0,0] # 对符合参数的嫁情况计数
        self.counter_not_marry = [0,0,0,0] # 对符合参数的不嫁情况计数
​
    def prior(self):
        for x in xrange(1,10):
            pass
    def likelihood(self):
        for x in range(self.sample_size):
            if self.data[x][-1] == 1:
                self.marry+=1 # 嫁的总数
                for i in range(len(self.user)):
                    if self.data[x][i] == self.user[i]:
                        self.counter_marry[i]+=1
            else:
                for i in range(len(self.user)):
                    if self.data[x][i] == self.user[i]:
                        self.counter_not_marry[i]+=1
    def calc(self):
        # 计算概率
        # left 是 P(A) * P(B|A),right 是 P(B|A') * P(A')
        left = 1 ; right = 1 
        self.not_marry = self.sample_size - self.marry
        for x in range(len(self.counter_marry)):
            left *= self.counter_marry[x] / self.marry
            right *= self.counter_not_marry[x] / self.not_marry
        left *= self.marry / self.sample_size
        right *= self.not_marry / self.sample_size
        return left / (left+right)
    def print(self,*args):
        self.user = args
        self.likelihood()
        PR = self.calc()
        if PR < 0.5:
            self.yes_or_not = 0
        print("这个男人「不帅,性格不好,矮,不上进」嫁吗\n")
        if self.yes_or_not == 1:
            print("嫁!")
            print("P(嫁|不帅、性格不好、矮、不上进)={:.2%}".format(PR))
            print("P(不嫁|不帅、性格不好、矮、不上进)={:.2%}".format(1-PR))
        else:
            print("不嫁!")
            print("P(嫁|不帅、性格不好、矮、不上进)={:.2%}".format(PR))
            print("P(不嫁|不帅、性格不好、矮、不上进)={:.2%}".format(1-PR))
def main():
    帅 = 1; 不帅 = 0;性格好 = 1;性格不好 = 0;高 = 1;矮 = 0;上进 = 1;不上进 =0;嫁 = 1; 不嫁 = 0;
    data = [[帅,性格不好,矮,不上进,不嫁],
    [不帅,性格好,矮,上进,不嫁],
    [帅,性格好,矮,上进,嫁],
    [不帅,性格好,高,上进,嫁],
    [帅,性格不好,矮,上进,不嫁],
    [不帅,性格不好,矮,不上进,不嫁],
    [帅,性格好,高,不上进,嫁],
    [不帅,性格好,高,上进,嫁],
    [帅,性格好,高,上进,嫁],
    [不帅,性格不好,高,上进,嫁],
    [帅,性格好,矮,不上进,不嫁],
    [帅,性格好,矮,不上进,不嫁]]
    a = naive_bayes(data)
    a.print(不帅,性格不好,矮,不上进)
if __name__ == '__main__':
    main()

运行结果:

image

结言:

因为数据比较少,只用了内置的列表存放数据,没有用numpy这样的库。更骚的是,我用了中文变量(没错,Python支持中文变量)。写这篇笔记,也是在实践费曼技巧,以教促学。如果笔记有错误,麻烦回复提醒下,我会改正!

参考文献:

  1. https://blog.csdn.net/fisherming/article/details/79509025
上一篇下一篇

猜你喜欢

热点阅读