利用贝叶斯判别函数设计分类器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27914913/article/details/63691926

详情请参阅《模式分类》第二版第二章上机练习2.5节第2题

数据说明:

有w1,w2,w3三组样本数据如下(符合正态分布):
这里写图片描述这里写图片描述这里写图片描述

(1)假设P(w1)=P(w2)=0.5,P(w3)=0,仅利用x1特征值为这两类判别设计一个分类器,并确定样本的经验训练误差,即误分点的百分比。
(2)假设P(w1)=P(w2)=0.5,P(w3)=0,利用x1,x2两个特征值为这两类判别设计一个分类器,并确定样本的经验训练误差,即误分点的百分比。
(3)假设P(w1)=P(w2)=0.5,P(w3)=0,利用x1,x2和x3三个特征值为这两类判别设计一个分类器,并确定样本的经验训练误差,即误分点的百分比。

实验步骤:

由于这两类数据符合正态分布,可以求出每一类数据的均值mu和协方差sigma,然后我们利用课本第二章式(49)的判别函数来对每一个样本数据进行判别分类。原本在w1类的数据点被分进w2或原本在w2的数据点被分进w1的那部分即为误分的数据点,误分点的百分比即为误分的数据点个数占全部数据的百分比。
由于我们在进行判别的时候会频繁用到式(49)的判别函数,因此我们将其写成一个函数,需要的时候调用即可。Matlab程序如下:

function r=discriminant_function(x,u,sigma,P)
% Inputs:
%   x      - Input vector:d*1
%   u      - Mean of distribution:d*1
%   sigma - Covariance matrix of distribution:d*d
%   P      - Prior probability
% Ouputs:
%   r      - Discriminant result
r= -0.5*((x - u)'/sigma)*(x - u) - size(u, 1)/2.0*log(2*pi) - 0.5*log(det(sigma)) + log(P);
end

需要注意的是,输入向量x是d维列向量,均值u是d维列向量,sigma是d*d的方阵。
现在考虑(1),利用一个特征向量,在matlab中取w1中的第一列作为x1,取w2中的第一列作为x2,利用mean函数求其均值,cov函数求其协方差(由于一维,协方差即方差):

load sample.mat
x1=w1(:,1);
x2=w2(:,1);
mu1=mean(x1);mu2=mean(x2);
sigma1=cov(x1);sigma2=cov(x2);

求出均值方差后,调用上述dicriminant_function判别函数比较大小后分类,分类结果存于result1和result2中,result1和result2均为列向量:

num_sample1=size(x1,1);num_sample2=size(x2,1);
result1=zeros(num_sample1,1);result2=zeros(num_sample2,1);%存储分类结果
%开始分类
for i=1:num_sample1
    if(discriminant_function(x1(i,:),mu1,sigma1,0.5)>=discriminant_function(x1(i,:),mu2,sigma2,0.5))
        result1(i,1)=1;  %分给类别1
    else
        result1(i,1)=2;  %分给类别2
    end
end
for i=1:num_sample2
    if(discriminant_function(x2(i,:),mu2,sigma2,0.5)>=discriminant_function(x2(i,:),mu1,sigma1,0.5))
        result2(i,1)=2;  %分给类别2
    else
        result2(i,1)=1;  %分给类别1
    end
end

分类结束后,需要找出误分的数据点,result1中类别为2和result2中类别为1的数据点均为误分点,可利用find函数,find函数返回n个匹配项的索引,为n*1的列向量,将误分点相加除于总数据点即为误分率,最后为了将数据点和类别显示出来,用disp函数打印出来。Matlab程序如下:

num_error=size(find(result1==2),1)+size(find(result2==1),1);
%find函数返回n个匹配项的索引,为n*1的列向量
error=num_error/(num_sample1+num_sample2);
disp('    w1.x1     class');
X=[x1 result1];
disp(X);  %输出w1分类结果
disp('    w2.x1     class');
Y=[x2 result2];
disp(Y);   %输出w2分类结果
fprintf('训练误差:%f\n',error);

最后的结果截图如下图1:

这里写图片描述

由结果可看出,w1中属于w2和w2中属于w1的数据点共有6个,因此误分比为:6/20=0.3。
现在来考虑利用两个特征值,大体思想都一样,区别就是输入向量x是二维,均值也是二维,协方差矩阵为2*2:

load sample.mat
x1=w1(:,1:2);  %两个特征值
x2=w2(:,1:2);
mu1=mean(x1',2);mu2=mean(x2',2);
sigma1=cov(x1);sigma2=cov(x2);

这里需要注意的是,均值向量是列向量,因此求均值mean的时候需要先转置(‘),cov函数的输入是n*d的矩阵,n是样本的个数,d是数据的维数,因此不需转置。核心部分与一维差不多,只需注意把输入变量x转置为列向量:

num_sample1=size(x1,1);num_sample2=size(x2,1);
result1=zeros(num_sample1,1);result2=zeros(num_sample2,1);  
%存储分类结果
%开始分类
%调用discriminat_fuction的时候注意输入向量x是列向量
for i=1:num_sample1
    if(discriminant_function(x1(i,:)',mu1,sigma1,0.5)>=discriminant_function(x1(i,:)',mu2,sigma2,0.5))
        result1(i,1)=1;  %分给类别1
    else
        result1(i,1)=2;  %分给类别2
    end
end
for i=1:num_sample2
    if(discriminant_function(x2(i,:)',mu2,sigma2,0.5)>=discriminant_function(x2(i,:)',mu1,sigma1,0.5))
        result2(i,1)=2;  %分给类别2
    else
        result2(i,1)=1;  %分给类别1
    end
end

接着计算误分比:

%计算训练误差
num_error=size(find(result1==2),1)+size(find(result2==1),1);%find函数返回n个匹配项的索引,为n*1的列向量
error=num_error/(num_sample1+num_sample2);
disp('    w1.x1     w1.x2     class');
X=[x1 result1];
disp(X);  %输出w1分类结果
disp('    w2.x1     w2.x2     class');
Y=[x2 result2];
disp(Y);   %输出w2分类结果
fprintf('训练误差:%f\n',error);

输出结果如下图2:

这里写图片描述

由上图可看出,二维误分比为0.45,比一维误分比0.3大。

对于三维情况,与二维基本一样,这里不再赘述。图3是三维情况下的结果:

这里写图片描述

由上图看出,三维情况下,误分比为0.15。

结论分析:

由以上实验结果可知,一维误分比0.3,二维误分比为0.45,三维为0.15。因此,对于一有限数据集,有可能在更高的数据维数下训练误差会增加。我猜想,可能是因为增加的特征值与已有的特征值之间不独立,会相互影响,具体内在的缘由现在还不太清楚。

猜你喜欢

转载自blog.csdn.net/qq_27914913/article/details/63691926