一、理论部分
1.1贝叶斯原理产生背景:
贝叶斯原理是英国数学家托马斯·贝叶斯提出的,他写的一篇关于归纳推理的论文直接影响了接下来两个多世纪的统计学,是科学史上著名的论文之一。贝叶斯原理是贝叶斯为了解决一个叫“逆向概率”问题写了一篇文章,尝试解答在没有太多可靠证据的情况下,怎样做出更符合数学逻辑的推测。
1.2贝叶斯原理涉及的概念及计算:
这实际上涉及到了贝叶斯原理中的几个概念:
①先验概率:通过经验来判断事情发生的概率,X的先验概率表示为P(X),Y的先验概率表示为P(Y)。
②后验概率:后验概率就是发生结果之后,推测原因的概率。
③条件概率:事件 A 在另外一个事件 B 已经发生条件下的发生概率,表示为 P(A|B),读作“在 B 发生的条件下 A 发生的概率”。
④似然函数(likelihood function): 概率模型的训练过程可以理解为求参数估计的过程,似然函数就是用来衡量这个模型的参数。似然在这里就是可能性的意思,它是关于统计参数的函数。
假如有两个事件A、B,如果已知A事件发生时B事件的发生概率P(B|A)以及A、B发生的概率P(A)、P(B),根据贝叶斯决策理论能计算出在B事件发生的条件下A事件的概率P(A|B).计算公式如下:
1.3贝叶斯分类:![](https://i-blog.csdnimg.cn/blog_migrate/2aec23dee6bdb0f8bb4f6e63188299f6.png)
二、朴素贝叶斯分类
2.1原理介绍:
朴素贝叶斯是一种简单但极为强大的预测建模算法 ,之所以称为朴素贝叶斯,是因为它假设每个输入变量是独立的。这是一个强硬的假设,实际情况并不一定,但是这项技术对于绝大部分的复杂问题仍然非常有效。朴素贝叶斯分类是一种有监督的分类算法,可以进行二分类,或者多分类。
朴素贝叶斯模型由两种类型的概率组成:
①每个类别的概率P(Cj);
②每个属性的条件概率P(Ai|Cj)。
2.2数学表达式:
2.3算法步骤:
Step1:找出样本中出现的所有特征属性featList,并计算每种类别的概率Pi
Step2:把样本的特征向量转化为以featList相同长度的只包含0、1的向量,其中1代表该 样本中出现了featList中的该属性;0代表没有出现
Step3:计算每种类别的样本每个特征出现的概率
Step4:根据每个样本中的特征属性出现的情况计算它是每种类别的概率选出其中最大的作 为该样本的特征。
Step5:对数据集中所有样本进行分类,计算预测的准确率
训练过程就是基于训练集D来估计类先验概率P(c),并为每个属性估计条件概率
在实际的应用中,根据特征变量是离散的还是连续的,使用不同的模型处理,需要用到最大似然估计的估计方法。
2.4朴素贝叶斯常用的模型及应用情况:
①高斯模型:处理特征是连续型变量的情况
②多项式模型:最常见,要求特征是离散数据
③伯努利模型:要求特征是离散的,且为布尔类型,即true和false,或者1和0
三、实现
3.1举个简单的栗子:判断员工是否是公司高层?
随机抽取10人。现有特征(a1,a2,a3,b) 。a1:年龄是否大, a2:工龄是否长,a3:学历是否高。b:是否高层(0代表否,1代表是)
(0,0,0,0)
(0,0,0,0)
(0,0,0,0)
(0,0,1,0)
(0,1,1,0)
(1,0,0,0)
(0,1,0,0)
(0,0,1,1)
(0,1,1,1)
(1,1,1,1)
【数据自己想的,实际数据要根据实际获取】
现在随机抽一个人,他年龄大,工龄长,学历高。预测他是否属于高层?
解:计算概率
P(是高层|所有数据集) = 3/10 P(不是高层|所有数据集)= 7/10
P(年龄大|是高层)= 1/3 P(工龄长|是高层)= 2/3 P(学历高|是高层) = 1/1
P(年龄大|不是高层)= 1/7 P(工龄长|不是高层)= 2/7 P(学历高|不是高层) = 2/7
假设他是属于高层:
P1 = P(是高层|所有数据集) * P(年龄大|是高层)* P(工龄长|是高层)* P(学历高|是高层)
= 3/10 * 1/3 * 2/3 * 1/1 = 6/90 = 0.0667
假设他不属于高层:
P0 = P(是高层|所有数据集)*P(年龄大|是高层)* P(工龄长|是高层)*P(学历高|是高层)
= 7/10 * 1/7 * 2/7 * 2/7 = 28/3430 = 0.00816
由 P1 > P0:
我们预测他属于高层
我们用10组数据(训练集)的分布,估计出全公司的人员分布。利用分布各个特征互相独立。计算出概率,哪种概率大 我们预测新的样本属于哪一类。下面用代码来实现下。
3.2代码解释
先来看下完整的代码
import numpy as np
class BayesModel():
def __init__(self):
super(BayesModel,self).__init__()
self.ng_result = [] # 存放ng的概率
self.ok_result = [] # 存放ok的概率
def probability(self,a,b):
p_a = a/(a+b)
p_b = 1-p_a
return p_a,p_b
def fit(self,x,y):
columns = x.shape[1] # 为了获取特征的数量,我们上述例子是3个特征 (年龄,工龄,学历)
data = np.c_[x,y] # 连接到同一个numpy,方便操作
ng_data = data[(data[:,-1] == 0)] # 把结果ng的数据取出来
ok_data = data[(data[:,-1] == 1)] # 把结果ok的数据取出来
ng_len,ok_len = ng_data.shape[0],ok_data.shape[0]
self.ng,self.ok = self.probability(ng_len,ok_len)
for i in range(columns):
ng_len_ng = ng_data[(ng_data[:,i] == 0)].shape[0]
ng_len_ok = ng_len - ng_len_ng
ok_len_ng = ok_data[(ok_data[:,i] == 0)].shape[0]
ok_len_ok = ok_len - ok_len_ng
self.ng_result.append(self.probability(ng_len_ng,ng_len_ok))
self.ok_result.append(self.probability(ok_len_ng,ok_len_ok))
def predict(self,data_data):
list_result = [] # 存放预测的结果
for datas in data_data:
ng,ok = self.ng,self.ok
for index,data in enumerate(datas):
if data == 0:
ng = ng*self.ng_result[index][0]
ok = ok*self.ok_result[index][0]
else:
ng = ng*self.ng_result[index][1]
ok = ok*self.ok_result[index][1]
if ng>ok:
list_result.append(0)
else:
list_result.append(1)
return list_result
if __name__ == '__main__':
x1 = np.array([0,0,0,0,0,1,0,0,0,1]).reshape(-1,1)
x2 = np.array([0,0,0,0,1,0,1,0,1,1]).reshape(-1,1)
x3 = np.array([0,0,0,1,1,0,0,1,1,1]).reshape(-1,1)
x = np.c_[x1,x2,x3]
y = np.array([0,0,0,0,0,0,0,1,1,1]).reshape(-1,1)
print(x)
print(y)
bayes = BayesModel()
bayes.fit(x,y)
predict = bayes.predict([[1,1,1],[0,1,1],[1,1,0]])
print(bayes.predict(x)) # 预测下我们的训练集
定义一个函数,因为我们是二分类结果是yes/no,特征也只有yes/no。所以我们定义个求概率的函数。这个比较简单。输入两个值如4,1 返回两个概率值0.8,0.2。
def probability(self,a,b):
p_a = a/(a+b)
p_b = 1-p_a
return p_a,p_b
构建模型,把概率数据保存到对应的列表里。
1、先算出结果为ng与ok的数据概率。并把这两部分数据提取出来,ng_data,ok_data
2、对ng_data,ok_data计算出各个特征的ng/ok的概率,并存入相应的列表里。
def fit(self,x,y):
columns = x.shape[1] # 为了获取特征的数量,我们上述例子是3个特征 (年龄,工龄,学历)
data = np.c_[x,y] # 连接到同一个numpy,方便操作
ng_data = data[(data[:,-1] == 0)] # 把结果ng的数据取出来
ok_data = data[(data[:,-1] == 1)] # 把结果ok的数据取出来
ng_len,ok_len = ng_data.shape[0],ok_data.shape[0]
self.ng,self.ok = self.probability(ng_len,ok_len)
for i in range(columns):
ng_len_ng = ng_data[(ng_data[:,i] == 0)].shape[0]
ng_len_ok = ng_len - ng_len_ng
ok_len_ng = ok_data[(ok_data[:,i] == 0)].shape[0]
ok_len_ok = ok_len - ok_len_ng
self.ng_result.append(self.probability(ng_len_ng,ng_len_ok))
self.ok_result.append(self.probability(ok_len_ng,ok_len_ok))
这段是预测,由函数fit已经构建完模型,数据存到列表。现在想预测新的样本集。
先看传入进来的data_data是几组数据,然后每组数据进行枚举,概率相乘,最后判断ng与ok那种概率大。最后返回出整个结果。思路和整个代码都比较简单。
def predict(self,data_data):
list_result = [] # 存放预测的结果
for datas in data_data:
ng,ok = self.ng,self.ok
for index,data in enumerate(datas):
if data == 0:
ng = ng*self.ng_result[index][0]
ok = ok*self.ok_result[index][0]
else:
ng = ng*self.ng_result[index][1]
ok = ok*self.ok_result[index][1]
if ng>ok:
list_result.append(0)
else:
list_result.append(1)
return list_result
数据集用的是上述判断是否为高层的数据。
if __name__ == '__main__':
x1 = np.array([0,0,0,0,0,1,0,0,0,1]).reshape(-1,1)
x2 = np.array([0,0,0,0,1,0,1,0,1,1]).reshape(-1,1)
x3 = np.array([0,0,0,1,1,0,0,1,1,1]).reshape(-1,1)
x = np.c_[x1,x2,x3]
y = np.array([0,0,0,0,0,0,0,1,1,1]).reshape(-1,1)
print(x)
print(y)
bayes = BayesModel()
bayes.fit(x,y)
predict = bayes.predict([[1,1,1],[0,1,1],[1,1,0]])
3.2、完整代码
import numpy as np
class BayesModel():
def __init__(self):
super(BayesModel,self).__init__()
self.ng_result = [] # 存放ng的概率
self.ok_result = [] # 存放ok的概率
def probability(self,a,b):
p_a = a/(a+b)
p_b = 1-p_a
return p_a,p_b
def fit(self,x,y):
columns = x.shape[1] # 为了获取特征的数量,我们上述例子是3个特征 (年龄,工龄,学历)
data = np.c_[x,y] # 连接到同一个numpy,方便操作
ng_data = data[(data[:,-1] == 0)] # 把结果ng的数据取出来
ok_data = data[(data[:,-1] == 1)] # 把结果ok的数据取出来
ng_len,ok_len = ng_data.shape[0],ok_data.shape[0]
self.ng,self.ok = self.probability(ng_len,ok_len)
for i in range(columns):
ng_len_ng = ng_data[(ng_data[:,i] == 0)].shape[0]
ng_len_ok = ng_len - ng_len_ng
ok_len_ng = ok_data[(ok_data[:,i] == 0)].shape[0]
ok_len_ok = ok_len - ok_len_ng
self.ng_result.append(self.probability(ng_len_ng,ng_len_ok))
self.ok_result.append(self.probability(ok_len_ng,ok_len_ok))
def predict(self,data_data):
list_result = [] # 存放预测的结果
for datas in data_data:
ng,ok = self.ng,self.ok
for index,data in enumerate(datas):
if data == 0:
ng = ng*self.ng_result[index][0]
ok = ok*self.ok_result[index][0]
else:
ng = ng*self.ng_result[index][1]
ok = ok*self.ok_result[index][1]
if ng>ok:
list_result.append(0)
else:
list_result.append(1)
return list_result
if __name__ == '__main__':
x1 = np.array([0,0,0,0,0,1,0,0,0,1]).reshape(-1,1)
x2 = np.array([0,0,0,0,1,0,1,0,1,1]).reshape(-1,1)
x3 = np.array([0,0,0,1,1,0,0,1,1,1]).reshape(-1,1)
x = np.c_[x1,x2,x3]
y = np.array([0,0,0,0,0,0,0,1,1,1]).reshape(-1,1)
print(x)
print(y)
bayes = BayesModel()
bayes.fit(x,y)
predict = bayes.predict([[1,1,1],[0,1,1],[1,1,0]])
print(bayes.predict(x)) # 预测下我们的训练集看下结果
3.3改进思路
1、如何实现多分类。
这部分只有二分类,要想多分类就不能只是0与1这么简单。模型要兼容多分类,可以对结果集利用np.unique(),然后取出值进行分类。特征单个种类分类多,也可以使用这种方法。如果比如身高这些特征符合正态分布,需要用正态分布概率进行计算。
2、可以发现,如果通过此数据集,P(学历不高|是高层)= 0,因为我们是连乘计算概率,所以会出现一种情况是,只要他学历不高,那么他是高层概率为0。按照常理讲这是不合理的。解决方式:增加数据训练集;拉普拉斯平滑处理,调整probability 函数计算概率的方式 ,分子加一,分母加特征种数。这部分也比较简单,具体可以参考文章开头说的。
3、如何提升预测准度。
3.1、提高训练集数据的质量。基本所有机器学习对训练集的数据要求都很高,贝叶斯更是如此,如果你选取的数据质量不高,没有代表性,抽选随机性不高。对模型影响很大。
3.2、增加训练集的数量。这个非常好理解,我们投硬币,投的次数越多,正面概率越解决1/2。更接近真实值。
3.3、选取特征。关于如何选取特征,这里不进行深度讨论。我们只针对例题,我们选取年龄大,工龄长,学历高是否合理。我们知道贝叶斯假设是各个特征独立,那么我们选取特征的时候尽量不要有冗余,特征之间相关性不要太大。