详情请参阅《模式分类》第二版第二章上机练习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。因此,对于一有限数据集,有可能在更高的数据维数下训练误差会增加。我猜想,可能是因为增加的特征值与已有的特征值之间不独立,会相互影响,具体内在的缘由现在还不太清楚。