失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 贝叶斯分类器的matlab实现_贝叶斯实验

贝叶斯分类器的matlab实现_贝叶斯实验

时间:2023-11-05 15:46:08

相关推荐

贝叶斯分类器的matlab实现_贝叶斯实验

贝叶斯实验

Part 1.仿真实验

随机产生10000组正样本和20000负样本高斯分布的数据集合(维数设为二维),要求正样本:均值为[1;3],方差为[2 0;0 2];负样本:均值为[10;20],方差为[10 0;0 10]。先验概率按样本量设定为1/3和2/3.分别利用最小错误概率贝叶斯分类器和最小风险概率贝叶斯分类器对其分类。(假设风险程度正样本分错风险系数为0.6,负样本分错风险为0.4,该设定仅用于最小风险分析)2

Part 2. 实际应用—汽车评价分类

给定汽车评价数据集,下载链接:http://archive.ics.uci.edu/ml/datasets/Car+Evaluation,利用贝叶斯算法进行数据分类操作,并统计其预测正确率。 (1)数据描述 共1728个数据,每个数据特征为6维,分为4类,类别标记为unacc,acc,good,V-good 四个类别标记分别表示汽车性价比等级(由低到高) unacc:1210个 acc:384个 good:69个 V-good:65个 6个特征分别为:(6个属性) 1、buying (取值:v-high、high、med、low) 表示购买价格 2、maint (取值: v-high、high、med、low) 表示维修价格 3、door (取值:2、3、4、5-more) 车门数量 4、Persons (取值:2、4、more) 可容纳人数 5、Lug_boot (取值:small、med、big) 行李箱大小 6、Safety (取值:low、med、high) 安全系数 (2)实验完成要求 1. 仔细阅读实验说明并了解数据集; 2. 使用任何一种熟悉的计算机语言(比如 C,Java或者MATLAB)实现朴素贝叶斯算法; 3. 利用10折交叉验证,对所设计的贝叶斯分类器进行性能评估; 4. 提交代码,统计并分析实验结果,上交实验报告;

实验过程

贝叶斯公式 $large P(omega{_i}|x)= large{ P(x|omega_i)P(w_i) over sum P(x|omega_i)P(w_i)}$

因为分母是一定的,公式可以写成 : $large P( omega{_i}|x) ∝ P(x|omega_i)P(w_i)$

因为$P(x|omega_i)$在实际中无法从有限的样本中估计而来,假设所有的特征相互独立(即使在理想条件下效果也是非常好的)得到朴素贝叶斯。

即:$large P( omega{_i}|x) ∝ P(x_1|omega_i)cdots P(x_n|omega_i)P(w_i)$

朴素贝叶斯的模型概率图表示(盘式记法) 贝叶斯最优分类器

考虑到样本误分类产生的损失,为其相应的分类加权。得到

条件风险:$R(omega_i|x) = sum lambda_{ij}P(omega_j|x)$

寻求一个判定准则最小化总体风险:$R(h)= E_x[ R(h(x)|x)]$

贝叶斯最优分类器: $h^*(x) = underset{omega}{argmax} P(omega_i|x)$

当目标是最小化分类错误率,其损失函数

$$lambda_{ij} begin{cases} 0 & text{if i=j} 1 & text{if i!=j}end{cases}$$

此时,条件风险为: $$R(omega|x) = 1-P(omega|x)$$

$$h*(x) = underset{omega}{argmin} P(omega_i|x)$$ 判别式模型与生成式模型

假设可观察到的变量集合为 $X$ 需要预测的变量集合为 $Y$ 其它的变量集合为 $Z$ 。 生成式模型判别式模型是直接对联合概率分布$P(X,Y,Z)进行建模在给定观测集合的$X$ 的条件下通过计算边缘概率分布进行推断。而判别式模型是直接求条件概率进行推断。 朴素贝叶斯是生成式模型。

贝叶斯方法封装

代码

import numpy as npclass Naive_bayes:'''我们需要计算先验概率,类条件密度概率,封装参数为标签和特征。'''num = 0feature_cat = 0label_cat= 0def __init__(self):passdef NaiveBayes(self,Py, Px_y, x):featrueNum = self.feature_catclassNum = self.label_cat# 建立存放所有标记的估计概率数组P = [0] * classNum# 对于每一个类别,单独估计其概率for i in range(classNum):# 初始化sum为0,sum为求和项。# 在训练过程中对概率进行了log处理,所以这里原先应当是连乘所有概率,最后比较哪个概率最大# 但是当使用log处理时,连乘变成了累加,所以使用sumsum = 0for j in range(featrueNum):if x[j] in Px_y[i][j]:sum += Px_y[i][j][x[j]]P[i] = sum + Py[i]return P.index(max(P))def cost_NaiveBayes(self, Py, Px_y, x,cost):featrueNum = self.feature_catclassNum = self.label_cat# 建立存放所有标记的估计概率数组P = [0] * classNumP_ = [0] * classNum# 对于每一个类别,单独估计其概率for i in range(classNum):# 初始化sum为0,sum为求和项。# 在训练过程中对概率进行了log处理,所以这里原先应当是连乘所有概率,最后比较哪个概率最大# 但是当使用log处理时,连乘变成了累加,所以使用sumsum = 0for j in range(featrueNum):if x[j] in Px_y[i][j]:sum += Px_y[i][j][x[j]]P[i] = sum + Py[i]for m in range(classNum):totall = 0for n in range(classNum):totall += P[n]*cost[m][n]P_[m] = totallreturn P_.index(min(P_))def Naive_test(self,Py, Px_y, test_data, test_label):# 错误值计数errorCnt = 0# 循环遍历测试集中的每一个样本for i in range(len(test_data)):# 获取预测值presict = self.NaiveBayes(Py, Px_y, test_data[i])# 与答案进行比较if presict != test_label[i]:# 若错误 错误值计数加1errorCnt += 1# 返回准确率return 1 - (errorCnt / len(test_data))def cost_Naive_test(self,Py, Px_y, test_data, test_label,cost):# 错误值计数errorCnt = 0# 循环遍历测试集中的每一个样本for i in range(len(test_data)):# 获取预测值presict = self.cost_NaiveBayes(Py, Px_y, test_data[i],cost)# 与答案进行比较if presict != test_label[i]:# 若错误 错误值计数加1errorCnt += 1# 返回准确率return 1 - (errorCnt / len(test_data))def fit(self,train_data, train_label):featureNum = train_data.shape[1]self.feature_cat = featureNumlabel = set(train_label)self.label_cat = len(label)classNum = len(label)Py = np.zeros((classNum, 1))# 计算先验概率分布label_dic = {}for i in label:# 若训练集中没有某一类的数据则其预测概率为零。加一保证不为零,还要同时保证分母不为零 确保预测概率不为零label_dic[i]=((np.sum(train_label == i)) + 1)Py[int(i)] = (label_dic[i]) / (len(train_label) + classNum)# 转换为log对数形式,防止数据下溢Py = np.log(Py)# 初始化为全0矩阵,用于存放所有情况下的条件概率Px_y = {}for i in range(classNum):Px_y[i] = {}for j in range(featureNum):Px_y[i][j] = {}for m in range(len(train_label)):label = train_label[m]x = train_data[m]for n in range(featureNum):# 这里还没有计算条件概率,先把所有数累加,全加完以后,在后续步骤中再求对应的条件概率if x[n] not in Px_y[label][n]:Px_y[label][n][x[n]] = 1else:Px_y[label][n][x[n]] += 1for label in range(classNum):for z in range(featureNum):l =len(Px_y[label][z].keys())for key,item in Px_y[label][z].items():Px_y[label][z][key] = np.log((item + 1) / (label_dic[label]) + l)# 返回先验概率分布和条件概率分布return Py, Px_y

主要思路 根据已知样本集训练分类器,求得先验概率和密度概率。 实验步骤 从汽车的数据集上可以看出,样本太少而其特征类别44433*3远高于某一类别的数量,若测试集中出现了原来没有出现过的特征,导致其Px_y的概率为0,比如good类别safety只有high和med。对实验结果也有一定的影响,若某个属性值在训练过程中没有与某个类同时出现过,则根据连乘式将会把其它属性携带的信息抹去,这是不可靠的。

使用上面通过这个例子折射处一个问题:训练集上,很多样本的取值可能并不在其中,但是这不并代表这种情况发生的概率为0,因为未被观测到,并不代表出现的概率为0 。在概率估计时,通常解决这个问题的方法是要进行平滑处理,常用拉普拉斯修正。拉普拉斯修正的含义是,在训练集中总共的分类数,用 N 表示;di 属性可能的取值数用 Ni 表示,因此原来的先验概率 P(c) 的计算公式由:

先验概率: $P(c) = large{c over C}$$P(c) = large{c+1 over C+N}$

条件概率: $P(x|c) = large{c_x over C_x}$ $P(x|c) = large{c_x+1 over C_x+N_i}$

该方法避免了因训练集样本的不充分而导致概率估计值为零的问题,在训练集变大时,修正所带来的影响可以忽略不计,使得估值趋近于实际概率值。贝叶斯估计

我们计算朴素贝叶斯,使用的是极大似然估计法去估计相应的概率,这会导致上面出现的问题,我们就用拉普拉斯修正,这就成为了贝叶斯估计。在理想条件下得到的就是贝叶斯最优分类器,但是由于先验概率和密度概率都是由样本估计得到的,所以存在一定的误差,也就是说样本越接近全集,或者其分布近似全集的分布,则其可以看做贝叶斯最优分类器,但样本是全集的话就没有意义。深度学习是样本集可以看做大到全集。 计算先验概率,后验概率时计算过程中取log运算,因为对数值小的部分差异的敏感程度比数值大的部分的差异敏感程度更高,这是符合常识的,化累法为累加便于计算,同时防止由于数据下溢而导致计算结果无法比较。

Part1

代码

from means.naive_bys import Naive_bayesimport numpy as npif __name__ == "__main__":mean1 = [1, 3]cov1 = [[2, 0], [0, 2]]X = np.around(np.random.multivariate_normal(mean1, cov1, 10000),3)mean2 = [10, 20]cov2 = [[10, 0], [0, 10]]Y = np.around(np.random.multivariate_normal(mean2, cov2, 20000),3)num = X.shape[0]num1 = Y.shape[0]train_data = np.vstack((X[:int(1/3*num)],Y[:int(1/3*num1)]))train_label = np.hstack((np.zeros(len(X[:int(1/3*num)])), np.zeros(len(Y[:int(1/3*num1)]))+1))test_data = np.vstack((X[int(1 / 3 * num):] , Y[int(1 / 3 * num1):]))test_label = np.hstack((np.zeros(len(X[int(1 / 3 * num):])), np.zeros(len(Y[int(1 / 3 * num1):])) + 1))naive_bys = Naive_bayes()Py, Px_y =naive_bys.fit(train_data, train_label)# 使用习得的先验概率分布和条件概率分布对测试集进行测试accuracy = naive_bys.Naive_test(Py, Px_y, test_data, test_label)print('1/3the accuracy is:', accuracy)accuracy = naive_bys.cost_Naive_test(Py, Px_y, test_data, test_label,[[0,0.6],[0.4,0]])print('1/3 cost the accuracy is:', accuracy)train_data = np.vstack((X[:int(2 / 3 * num)], Y[:int(2 / 3 * num1)]))train_label = np.hstack((np.zeros(len(X[:int(2 / 3 * num)])), np.zeros(len(Y[:int(2 / 3 * num1)])) + 1))test_data = np.vstack((X[int(2 / 3 * num):], Y[int(2 / 3 * num1):]))test_label = np.hstack((np.zeros(len(X[int(2 / 3 * num):])), np.zeros(len(Y[int(2 / 3 * num1):])) + 1))naive_bys = Naive_bayes()Py, Px_y = naive_bys.fit(train_data, train_label)# 使用习得的先验概率分布和条件概率分布对测试集进行测试accuracy = naive_bys.Naive_test(Py, Px_y, test_data, test_label)print('1/3the accuracy is:', accuracy)accuracy = naive_bys.cost_Naive_test(Py, Px_y, test_data, test_label,[[0,0.6],[0.4,0]])print('2/3t cost he accuracy is:', accuracy)

实验技巧

在生成数据时将数据取小数点后三位,否则的numpy生成的实验数据的小数位数太多不仅处理起来比较麻烦,计算也比较复杂。 * 实验结果

可以看到最小错误概率贝叶斯分类器准确率基本相等于最小风险概率贝叶斯分类器。

Part2

代码

from means.naive_bys.naive_bys import Naive_bayesfrom sklearn.model_selection import RepeatedKFoldfrom sklearn import preprocessingimport pandas as pdimport numpy as npif __name__ == "__main__":df = pd.read_csv("data/car.csv")raw_set = df.valueslabel_encoder = []# 放置每一列的encoder encoded_set = np.empty(raw_set.shape)for i, _ in enumerate(raw_set[0]):# 拟合每一列上的数据encoder = preprocessing.LabelEncoder()encoded_set[:, i] = encoder.fit_transform(raw_set[:, i])label_encoder.append(encoder)dataset_X=encoded_set[:,:-1].astype(int)dataset_y=encoded_set[:,-1].astype(int)print(np.sum(dataset_y==2))# 将数据集拆分为train set 和test setstart = time.time()naive_bys = Naive_bayes()# 使用习得的先验概率分布和条件概率分布对测试集进行测试kf = RepeatedKFold(n_splits=10)accuracy = 0for train_index, test_index in kf.split(dataset_X):train_X, train_y = dataset_X[train_index], dataset_y[train_index]test_X, test_y = dataset_X[test_index], dataset_y[test_index]Py, Px_y = naive_bys.fit(train_X, train_y)accuracy+= naive_bys.Naive_test(Py, Px_y, test_X, test_y)print('the accuracy is : %f' % (accuracy/100))

实验思路 由于给出的是标注数据集,但是其特征未进行处理,我们先将数据进行预处理,进行数据类型转换。最后用自己封装的贝叶斯方法进行10折交叉验证处理,得到实验结果。 交叉验证

交叉验证的基本思想是将数据集分为k等份,对于每一份数据集,其中k-1份用作训练集,单独的那一份用作测试集。在实际当中,进行一次k折交叉验证还是不够的,我们需要进行多次,比如我进行了10次10折交叉验证。

实验结果实验结果分析

实验数据的结果比较低,我认为是如下原因,

|class | N | N[%]| |------|-----------|------------| |unacc |1210 | (70.023 %) | |acc |384 | (22.222 %) | |good |69 |( 3.993 %) | |v-good |65 |( 3.762 %) | 1. Class Distribution (number of instances per class)

可以看到其数据并不是均匀分布的,unacc所占的比例极大导致了先验概率过高绝大多数的分类为unacc,使得分类的结果倾向于所占比例较大的类。

其他

其中data是汽车数据集,而means是封装过后的贝叶斯函数。

而means文件夹下的test.py是处理随机数的文件。load_data.py是处理car数据集的文件。

分析与总结

本次实验主要对贝叶斯方法进行实验,也只是实现了一小部分,贝叶斯分类种类很多,高斯和多项式等。对朴素贝叶斯有了更深刻的理解,在实际代码实现时,要考虑各种数据情况,并做出相应的处理,增强其健壮性。

算法优点:

算法逻辑简单,易于实现(算法思路很简单,只要使用贝叶斯公式转化即可!) 分类过程中时空开销小(假设特征相互独立,只会涉及到二维存储)

缺点:

朴素贝叶斯假设属性之间相互独立,这种假设在实际过程中往往是不成立的。在属性之间相关性越大,分类误差也就越大。

反思:

实验遇到了许多bug,参考了相当多的资料,包括numpy,pandas,sklearn,通过本次实验加深了对这些库的使用熟练度,也学到了相当多的知识,像产生的二维随机数特征若果不加以处理就会产生异常的数据库,每一个类条件密度概率都非常低,导致结果下溢报错,参考csdn,学习了数据的处理方法,还有sklearn的编码库,一开始我是使用的是python的replace操作去替代类型转换,但是相当麻烦,查找资料,发现了sklearn的解决方案等等。实验收获很大,在以后面临相同的问题时,知道该如何解决。

如果觉得《贝叶斯分类器的matlab实现_贝叶斯实验》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。