实验三:参数估计与非参数估计实验报告
一、实验目的
- 通过本次实验实现机器学习中常用的参数估计和非参数估计的方法
- 使用编程加深对最大似然估计、最大后验概率估计等方法的认识
- 建立数据集学习使用python对多元数据进行操作
二、代码框架
-
本次实验使用的函数框架如下:
1.Gaussian_function(x, mean, cov) #计算多维(这里是2维)样本数据的概率p(x|w),参数mean是已知的均值向量 #cov是已知的协方差矩阵,x是样本数据 2.Generate_Sample_Gaussian(mean, cov, P, label) #生成符合正态分布的数据,P是指的先验概率,label是类标签 3.Generate_DataSet(mean, cov, P) #根据先验概率生成数据集 4.Generate_DataSet_plot(mean, cov, P) #画出不同先验对应的散点图 5.Likelihood_Test_Rule(X, mean, cov, P) #似然率测试规则 6.Max_Posterior_Rule(X, mean, cov, P) #最大后验概率规则 7.repeated_trials(mean, cov, P1, P2) #单次实验求不同准则下的分类误差
三、代码详细说明
-
Gaussian_function(x, mean, cov)
函数功能:计算p(x|w)def Gaussian_function(x, mean, cov): det_cov = np.linalg.det(cov) # 计算方差矩阵的行列式 inv_cov = np.linalg.inv(cov) # 计算方差矩阵的逆 #计算概率p(x|w) p = 1/(2*np.pi*np.sqrt(det_cov))*np.exp(-0.5 * np.dot(np.dot((x - mean),inv_cov), (x - mean))) return p
这里使用了如下的公式:
d是指的数据的维数,这里是2;
Σ是指的协方差矩阵,这里是cov;
μ是指的均值向量这里是meannp.linalg的三个函数:
1.np.linalg.det() 求矩阵的行列式
2.np.linalg.inv() 求矩阵的逆
3.np.dot() 求两矩阵的乘积 -
Generate_Sample_Gaussian(mean, cov, P, label)
函数功能:生成符合正态分布的数据,P是指的先验概率,label是类标签def Generate_Sample_Gaussian(mean, cov, P, label): ''' mean 为均值向量 cov 为方差矩阵a P 为单个类的先验概率 return 单个类的数据集 ''' # round(x[,n=0]) 保留到几位小数 temp_num = round(1000 * P) # 生成一个多元正态分布矩阵 x, y = np.random.multivariate_normal(mean, cov, temp_num).T #x,y坐标,x和y矩阵均符合正态分布 #z表示每个点属于哪一类 z = np.ones(temp_num) * label X = np.array([x, y, z]) #X.T中每个元素都是有三个元素的列表,分别表示x值,y值,以及对应的标签 return X.T
multivariate_normal(mean, cov, size=None, check_valid=None, tol=None)
1.函数功能:生成一个多元正态分布矩阵
2.mean:正态分布的均值向量
3.cov:正态分布的协方差矩阵
4.size:矩阵的大小(数量,维度)
5.check_valid:如果cov不是半正定矩阵的处理方法,一共有三个值:warn(输出警告,仍出结果),raise(报错),ignore(或略错误)
6.tol:检查协方差矩阵奇异值时的公差 -
Generate_DataSet(mean, cov, P)
函数功能:根据先验概率生成数据集def Generate_DataSet(mean, cov, P): # 按照先验概率生成正态分布数据 # 返回所有类的数据集 X = [] label = 1 for i in range(3): # 把此时类i对应的数据集加到已有的数据集中 X.extend(Generate_Sample_Gaussian(mean[i], cov, P[i], label)) label += 1 i = i + 1 return X
注意这里
extend()
和append()
的区别:
1.append将括号中的参数作为一个元素添加到列表对象的后面,即便参数是一个列表也是同样
2.extend将不是序列类型(list,dict,tuple)的参数作为一个元素添加到列表对象的后面,如果是序列类型的参数,就将序列和列表合并放在列表的后面 -
Generate_DataSet_plot(mean, cov, P)
函数功能:画出不同先验对应的散点图def Generate_DataSet_plot(mean, cov, P): # 画出不同先验对应的散点图 xx = [] label = 1 # 将xx变为包含三类数据的数据集 for i in range(3): xx.append(Generate_Sample_Gaussian(mean[i], cov, P[i], label)) label += 1 i = i + 1 #在这时xx是一个有三个元素的列表,每个元素都是一个类 # 画图 plt.figure() if P==[1 / 3, 1 / 3, 1 / 3]: plt.title("X1分布图") else: plt.title("X2分布图") for i in range(3): #画出每类的样本向量(x,y) plt.plot(xx[i][:, 0], xx[i][:, 1], '.', markersize=4.) #画出每类的中心点(均值向量对应的点) plt.plot(mean[i][0], mean[i][1], 'r*') plt.show()#没有这句图像不显示 return xx
-
Likelihood_Test_Rule(X, mean, cov, P)
函数作用:使用似然率测试规则进行估计得准确率# 似然率测试规则 def Likelihood_Test_Rule(X, mean, cov, P): class_num = mean.shape[0] # 类的个数 num = np.array(X).shape[0] error_rate = 0 for i in range(num): p_temp = np.zeros(3) for j in range(class_num): # 计算样本i决策到j类的概率 p_temp[j] = Gaussian_function(X[i][0:2], mean[j], cov) p_class = np.argmax(p_temp) + 1 # 得到样本i决策到的类 if p_class != X[i][2]: error_rate += 1 return round(error_rate / num , 3)
这个函数分别计算数据集中的每个样本被决策到三个不同的类的概率
p_temp
,使用np.argmax()求出列表中值最大的元素的下标
index,index+1即为我们决策出的结果p_class,用p_class和样本真正的类别X[i][2]
比较,判断正确与否,计算准确率 -
Max_Posterior_Rule(X, mean, cov, P)
函数功能:使用最大后验概率规则进行估计得准确率##最大后验概率规则 def Max_Posterior_Rule(X, mean, cov, P): class_num = mean.shape[0] # 类的个数 num = np.array(X).shape[0] error_rate = 0 for i in range(num): p_temp = np.zeros(3) for j in range(class_num): # 计算样本i是j类的后验概率 p_temp[j] =Gaussian_function(X[i][0:2],mean[j],cov)*P[j] p_class = np.argmax(p_temp) + 1 # 得到样本i分到的类 if p_class != X[i][2]: error_rate += 1 return round(error_rate / num,3)
基本思路和似然率测试规则是一样的,但这里计算概率的函数是P(x|w)*P[i]
-
repeated_trials(mean, cov, P1, P2)
函数功能:单次实验求不同准则下的分类误差# 单次试验求不同准则下的分类误差 def repeated_trials(mean, cov, P1, P2): # 根据mean,cov,P1,P2生成数据集X1,X2 # 通过不同规则得到不同分类错误率并返回 # 生成N=1000的数据集 X1 = Generate_DataSet(mean, cov, P1) X2 = Generate_DataSet(mean, cov, P2) error = np.zeros((2, 2)) # 计算似然率测试规则误差 error_likelihood = Likelihood_Test_Rule(X1, mean, cov, P1) error_likelihood_2 = Likelihood_Test_Rule(X2, mean, cov, P2) error[0] = [error_likelihood, error_likelihood_2] # 计算最大后验概率规则误差 error_Max_Posterior_Rule = Max_Posterior_Rule(X1, mean, cov, P1) error_Max_Posterior_Rule_2 = Max_Posterior_Rule(X2, mean, cov, P2) error[1] = [error_Max_Posterior_Rule, error_Max_Posterior_Rule_2] return error
分别生成两组数据集,分别对这两个数据集进行不同规则下的分类误差分析,将结果存在
error
中并返回
四、实验步骤
1.基本要求
在两个数据集合上分别应⽤“似然率测试规则” 、“最⼤后验概率规则” 进⾏分类实验,计算分类错误率,分析实验结果。
-
1.根据题设设置我们所需要用到的参数
mean = np.array([[1, 1], [4, 4], [8, 1]]) # 均值数组 cov = [[2, 0], [0, 2]] # 协方差矩阵 num = 1000 # 样本个数 P1 = [1 / 3, 1 / 3, 1 / 3] # 样本X1的先验概率 P2 = [0.6, 0.3, 0.1] # 样本X2的先验概率
-
2.绘制散点图,观察样本分布
Generate_DataSet_plot(mean, cov, P1) # 画X1数据集散点图 Generate_DataSet_plot(mean, cov, P2) # 画X2数据散点图
结果如下:
-
3.进行十次试验观察试验结果
# 计算十次运算的总误差 error_all = np.zeros((2, 2)) # 测试times_num次求平均 times_num = 10 for times in range(times_num): error=repeated_trials(mean,cov,P1,P2) print("第{}次试验: 极似然规则 最大后验规则".format(times+1)) print("X1误差: \t{} \t{}".format(error[0][0],error[1][0])) print("X2误差: \t{} \t{}".format(error[0][1], error[1][1])) error_all += error # 计算平均误差 error_ave = np.around(error_all / times_num,4) print("平均误差: 极似然规则 最大后验规则") print("X1误差: \t{} \t{}".format(error_ave[0][0],error_ave[1][0])) print("X2误差: \t{} \t{}".format(error_ave[0][1],error_ave[1][1]))
结果如下
分析试验结果:1.当每个类的先验概率P相同或差别不大时,及似然率测试规则和最大后验概率规则分类结果相差不大
2.当先验概率相差较大时,及似然率规则更好一些