matlab-初探KNN识别

记录一下学校的作业,识别过程使用matlab的prtool包进行

KNN算法

KNN是通过测量不同特征值之间的距离进行分类。具体思路是:如果一个样本在特征空间中的k个(欧氏距离或马氏距离等)距离最近即特征空间中最邻近的样本中的大多数属于某一个类别,则该样本也属于这个类别,通常K是不大于20的整数。KNN算法中,所选择的的邻居都是已经正确分类的对象即原始训练数据。该方法在定类决策上只一句最邻近的一个或者几个样本的类别来决定带份样本所属的类别。简单地说在一个N维属性的空间内,哪一类点距离他的距离最近,或者是以它为半径的园内的电中数量最多的类别是哪个,我们就认为这个未知的点就属于该类别。所以KNN是通过依据k个对象中占优的类别进行决策,而不是单一的对象类别决策(k=1)。因此这个算法的结果很大程度上是由K决定的,对线性和聚类分布有较好的指标。在KNN中,通过计算对象间距来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,在这里距离一般使用欧氏距离或曼哈顿距离欧氏距离和曼哈顿距离表达式
这也是KNN的特点和优势所在。
KNN算法的思想总结一下:就是在训练集中数据和标签已知的情况下,输入测试数据,将测试数据的特征与训练集中对应的特征进行相互比较,找到训练集中与之最为相似的前K个数据,则该测试数据对应的类别就是K个数据中出现次数最多的那个分类,其算法的描述为:
1)计算测试数据与各个训练数据之间的距离;
2)按照距离的递增关系进行排序;
3)选取距离最小的K个点;
4)确定前K个点所在类别的出现频率;
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。

特征提取方法

简介

特征提取方法有很多种,这里采取欧式距离度量的特征提取方案。
由于原始特征的数量很大,或者说样本是处于一个高维空间中,通过映射(或变换)的方法可以用地位空间来表示样本,这个过程就叫做特征提取。映射后的特征叫而此特征,他们是原始特征的某种组合(通常是线性组合)。所谓特征提取在广义上就是指一种变换。若Y是测量空间,X是特征空间,则变换A:Y→X就叫做特征提取器。而从一组特征中挑选中一些最有效的特征以达到降低特征空间维数的目的,这个过程叫做特征选择。一般都是挑选对分类器最有影响的特征或采用其他数学方法来帅选并比较,找出最优分类信息的特征。通过对上述特征提取方法的分析,选在最有效的特征,作为新的特征。
特征选择与提取的任务是求出一组对分类最有效的特征,因此我们需要一个定量的准则(或称作判据)来衡量特征对分类的有效性。具体来说,把一个高维空间变换为地位空间的映射有很多,而哪种映射对分类最有利没需要一个比较标准。从D个原始特征中选择出d的特征的各种可能组合也是很多的,哪种组合的分类效果最好,也要有一个比较标准。
两个特征向量之间的距离使他们相似度的一种很好的度量。假设对应同一类别的样本在特征空间中聚集在一起,而不同类别的样本互相离得比较远,分类就比较容易实现。因此在给定维数为D的特征空间中,我们应采用这样的d个特征,他们使各类尽可能远地相互分开。在上一节中我们已经指出,假设用表示第wi类的第k个样本与wj类的第l个样本之间的距离,我们应该选择这样的特征x*,使c个类别个样本的平均距离为最大,即

具体步骤

假设有D个原始特征,希望通过线性映射压缩为d个特征:,其变换关系为,经过变换后的变为,对于来说使盘踞达到最大的变换W如下:
设矩阵的本征值为,按大小顺序排列为:

则选前d个本征值对应的本征向量作为W。即

此时为:

基本参数

各类样本均值向量mi:
样本类内离散度矩阵Si和总类内离散度矩阵Sw


样本类内离散度矩阵Sb

MATLAB编程实现

读取数据

将原始人脸处理并通过PCA降维后的训练和测试样本存入faceD和faceR
使用load 和importdata分别读取特征数据矩阵faceD和faceR和标签faceDR和faceDS,标签以元胞数组的形式读取。

Train_Data = load('faceR');
Test_Data = load('faceS');
Train_Label = importdata('faceDR');
Test_Label = importdata('faceDS');

无效数据去除

将值为全0的特征样本和标签丢失的样本清除:
打开faceR的一行显示第一列为编号,每一个数据都是按照索引一一对应的,因此第一列的编号属性没有存在的意义
在所有样本数据中,有的数据是缺失的即全为0,对于这些数据的样本和其对应的标签需要删除
在所有的标签数据中,有的标签为(_missing descriptor),这也是无效数据,对于这些标签和对应的数据需要删除。观察数据发现一般数据包括大量的信息,因此对元胞数组进行长度分析大于上述字符串长度为20的标签即为正确标签
all(A,dim) dim为1是行,dim为2是列,dim=1时返回向量,其中矩阵A中行不为0时返回1,否则返回0,对这个0 1 组成的向量,我们直接对为0的行进行删除即可

Train_Data(:,1) = [];               			%去掉第一列的数字索引
Test_Data(:,1) = [];
Train_Label(all(Train_Data==0,2)) = [];   	%特征为全0的无效数据去除
Train_Data(all(Train_Data==0,2),:) = [];                
Test_Label(all(Test_Data==0,2)) = [];
Test_Data(all(Test_Data==0,2),:) = [];    
len = length(Train_Data);                  	%标签无效去除                                         
for i=len:-1:1									%去除无效标签数据
	if length(char(Train_Label(i))) < 40
		Train_Data(i,:) = [];
		Train_Label(i) = [];
	end
end
len = length(Test_Data);                                           
for i=len:-1:1
	if length(char(Test_Label(i))) < 40
		Test_Data(i,:) = [];
		Test_Label(i) = [];
	end
end

建立样本标签

观察第一行标签:1223 (_sex male) (_age child) (_race white) (_face smiling) (_prop '())
样本标签内包含大量信息如性别、年龄、人种、表情我们选择一种作为结果标签存储即可。
matlab提供了字符串矩阵,叫做cell,元胞数组。这让我们可以对矩阵中字符串进行像c语言一般的操作。

b = cell(length(Train_Label),1);      				%元胞数组b存放标签
c = zeros(length(Train_Label),1);  
for i=1:length(Train_Label)
	a = strsplit(strtrim(char(Train_Label(i))));	%分割字符串,提取所需标签
	a = strsplit(char(a(leibie)),')');
	b(i) = a(1);
	if strcmp(char(b(i)),char(sex(1)))
		c(i) = 1;    											%创建数字标签c
	end 
end
Train_Label =  num2str(c);
b = cell(length(Test_Label),1);               		%存放标签
c = zeros(length(Test_Label),1);              		%数字标签建立:男->1  女->0
for i=1:length(Test_Label)
	a = strsplit(strtrim(char(Test_Label(i))));	%分割字符串,提取所需标签
	a = strsplit(char(a(leibie)),')');
	b(i) = a(1);
	if strcmp(char(b(i)),char(sex(1)))
		c(i) = 1;    											%创建数字标签c
	end 
end
Test_Label = num2str(c);

特征提取

按之前所述,选取的准则是特征值之和最大,同时满足其大于0的特征值所对应的的的特征向量
然而,从特征方程中发现仅第一维>>0,而其余均为大于0且为10^-19的小数,因此单纯地使用一个列向量即可

x0 = Train_Data;                        
x1 = Train_Data;                  			%tabulate(Train_Label)可查看出现次数
x0(all(Train_Label=='1',2),:) = [];      	%获得男女样本x0和x1
x1(all(Train_Label=='0',2),:) = [];     	%x0--女;x1--男
u0 = mean(x0);                             	%x0、x1样本均值
u1 = mean(x1);
for i=1:length(x0)
    x0(i,:) = x0(i,:) - u0;
end
for i=1:length(x1)
    x1(i,:) = x1(i,:) - u1;
end
Sw = zeros(99,99);                       	%类内离散度矩阵
for i=1:size(x0,1)
    Sw = Sw + x0(i,:)'*x0(i,:);
end
for i=1:size(x1,1)
    Sw = Sw + x1(i,:)'*x1(i,:);
end
Sb = (u0-u1)'*(u0-u1);
J = Sb/Sw;
[x,~] = eig(J);									%获取特征向量x
W = x(:,1);                                    %满足条件的转换矩阵W
Train_Data = (W' * Train_Data')';                
Test_Data = (W' * Test_Data')';

进行KNN分类

PRTools: http://prtools.org/prtools/prtools-overview/
从网上下载并添加prtools包后,使用其中的knnc函数进行训练,再用testc函数对knnc函数训练的分类器进行测试。

eknn = [];
for k=1:50
    train_data = prdataset(Train_Data,Train_Label);  	%创建knnc所需的数据集dataset
    test_data = prdataset(Test_Data,Test_Label);
    Knn = knnc(train_data,k);           							%创建分类器
    eknn(k) = 1 - testc(test_data,Knn);      				%k取不同值的分类准确率--testc返回的是错误率
end
x = 1:50;                               %图示
y = eknn(x);
plot(x,y,'b-*');
xlabel('k数值');
ylabel('正确率');
title('J5-KNN分类器');

总结

正确率并没有很高,根据我的分析,原因有以下几点:
(1)降维的数据已是二次特征即已经经过PCA处理,出现了最大的主成分,再通过降维处理,就会出现只有一味的情况,即把高维数据降到一维,仅保留单个分类效果最大的特征,这不仅会使数据耦合变差,且在一维空间里,会存在很多离散的点,虽然总体聚集的中心离散度比较大,但是中间交叉的多,也会导致正确率大大降低。
(2)取得最大值的k值较大,一般k取值都在20以内,原因可能是降维后的数据具有较大的耦合性。
由于第一次接触,对于数据并不是很敏感,抛开任务驱动外,应该对数据进行更多的分析。
由于存在第三方库,在python上进行此次任务的编程就更为简单了。
感觉到的乐趣更多是在数据处理方面,每小小次的解决让自己感到兴奋和喜悦。也让我对matlab这个强大的矩阵处理工具有了初步的使用。使用matlab简单,用好matlab并不简单

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值