朴素贝叶斯分类器笔记-Python实现
前言:
上篇笔记介绍了贝叶斯原理,写这篇笔记,算是承上启下,更深入的学习下贝叶斯原理并应用它。同样,我用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支持中文变量)。写这篇笔记,也是在实践费曼技巧,以教促学。如果笔记有错误,麻烦回复提醒下,我会改正!
参考文献: