k-Nearest Neighbor algorithm
右图中,绿色圆要被决定赋予哪个类,是红色三角形还是蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相 似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决 策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方 法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成正比。
该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量 很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。因此可以采用权值的方法(和该样本距离小的邻居权值大)来改进。该方法 的另一个不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。目前常用的解决方法是事先对已知样 本点进行剪辑,事先去除对分类作用不大的样本。该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误 分。
相比于之前介绍的SVM及BP算法,KNN算法思想比较简单,它没有训练出模板model,然后利用model进行测试的过程,而是直接就是训练,利用已知的有标记的样本,进来一个样本就计算它与这些已知样本的距离,然后对这些距离中挑K个最小的进行投票,看K个最接近的样本中哪一个样本所占的个数多,就判断为哪一类。
前面也提到了KNN算法的一个当样本不平衡时,如一个类的样本容量很大,而其他类样本容量 很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数,为此我觉得可以在每类中随机抽取相同的样本数进行重组成新的样本,然后再进行KNN算法,记为改进方法1,或者调节距离的权重,距离越小的投票时的权重值就越大,记为改进方法2。下面是KNN算法的MATLAB代码,及没有用随机抽样的方法进行的试验结果(三类数据分别为150 50 50),和改进方法1,及改进方法2的结果对比。
未改进的结果,由于其中一类样本是150个,其他两类是50,所以数据有偏斜,结果为:
整体分类精度为:0.90476
类别1的分类精度为:0.94118
类别2的分类精度为:0.58824
类别3的分类精度为:1
改进方法一,随机抽样组成新的样本,新样本中,各类的样本数相同。结果为:
整体分类精度为:0.94048
类别1的分类精度为:0.94118
类别2的分类精度为:0.76471
类别3的分类精度为:1
改进方法二,增大最小距离的投票权重,当然也可能是我的权重选的不合适,结果为:
整体分类精度为:0.90476
类别1的分类精度为:0.94118
类别2的分类精度为:0.58824
类别3的分类精度为:1
可见和没加权重的未改进结果相同,当然我也试过好多数值,如果不当,精度还会下降。
把改进方法一和改进方法二相结合的结果:
整体分类精度为:0.90476
类别1的分类精度为:0.94118
类别2的分类精度为:0.76471
类别3的分类精度为:0.94
只是类别三的精度相对于改进方法一有所下降,所以看来还是样本数据的分均匀程度对分类的结果影响比较大。
下面是程序的源代码:
clear all;
close all;
clc;
load D:\硕士学习资料3\硕士毕设资料\区域生长等分割算法程序\遗传分割\MYGAseg\特征选择\traindata.mat
load D:\硕士学习资料3\硕士毕设资料\区域生长等分割算法程序\遗传分割\MYGAseg\特征选择\testdata.mat
load D:\硕士学习资料3\硕士毕设资料\区域生长等分割算法程序\遗传分割\MYGAseg\特征选择\trainlabel.mat
load D:\硕士学习资料3\硕士毕设资料\区域生长等分割算法程序\遗传分割\MYGAseg\特征选择\testlabel.mat
traindata=traindata(1:99,:);
trainlabel=trainlabel(1:99,1);
[predictlabel,acc]=myKNN(traindata,trainlabel,testdata,testlabel,15);
function [predictlabel,acc]=myKNN(traindata,trainlabel,testdata,testlabel,K)
[mtrain,ntrain]=size(traindata);
[mtest,ntest]=size(testdata);
juli=zeros(mtest,mtrain);%每一行存储的是一个样本与所有训练样本的距离
sortjuli=zeros(mtest,mtrain);
zuobiaojuli=zeros(1,mtest);
num1=0;
num2=0;
num3=0;
rightnum=0;%记录整体分类正确的个数
rightnum1=0;
rightnum2=0;
rightnum3=0;
for i=1:mtest
for j=1:mtrain
juli(i,j)=sqrt((sum(testdata(i,:)-traindata(j,:)).^2));%计算每个测试样本与每个训练样本的oushi距离
end
end
for i=1:mtest
[ sortjuli,zuobiaojuli]=sort(juli(i,:));%sort函数默认返回的是由小到大的排序结果
sorttrainlabel=trainlabel(zuobiaojuli);%标签也相应的改变顺序
ksortjuli(1,:)=sortjuli(1,1:K);%取距离和坐标的前k个
ksorttrainlabel=sorttrainlabel(1:K,1);
for j=1:K%统计前K个结果中那个的数目多
if j==1%如果是排在第一位的,也就是距离最小的,那么投票权重加大4
if ksorttrainlabel(j,1)==1
num1=num1+5;
end
if ksorttrainlabel(j,1)==2
num2=num2+5;
end
if ksorttrainlabel(j,1)==3
num3=num3+5;
end
elseif j==2%排在第二位的权重加大2,当然也可以自行改变
if ksorttrainlabel(j,1)==1
num1=num1+2;
end
if ksorttrainlabel(j,1)==2
num2=num2+2;
end
if ksorttrainlabel(j,1)==3
num3=num3+2;
end
else
if ksorttrainlabel(j,1)==1
num1=num1+1;
end
if ksorttrainlabel(j,1)==2
num2=num2+1;
end
if ksorttrainlabel(j,1)==3
num3=num3+1;
end
end
end
A=[num1 num2 num3];
Xsort=sort(A);%按照从小到大排序
if Xsort(1,end)==num1
predictlabel(i,1)=1;
elseif Xsort(1,end)==num2
predictlabel(i,1)=2;
elseif Xsort(1,end)==num3
predictlabel(i,1)=3;
end
if predictlabel(i,1)==testlabel(i,1)
rightnum=rightnum+1;
end
if predictlabel(i,1)==testlabel(i,1)&&testlabel(i,1)==1
rightnum1=rightnum1+1;
end
if predictlabel(i,1)==testlabel(i,1)&&testlabel(i,1)==2
rightnum2=rightnum2+1;
end
if predictlabel(i,1)==testlabel(i,1)&&testlabel(i,1)==3
rightnum3=rightnum3+1;
end
num1=0;%清0
num2=0;
num3=0;
end
leibie1=size(find(testlabel==1),1);%找出测试样本1的个数
leibie2=size(find(testlabel==2),1);
leibie3=size(find(testlabel==3),1);
acc1=rightnum1/leibie1;
acc2=rightnum2/leibie2;
acc3=rightnum3/leibie3;
acc=rightnum/mtest;%总体分类精度
disp(['整体分类精度为:',num2str(acc)]);
disp(['类别1的分类精度为:',num2str(acc1)]);
disp(['类别2的分类精度为:',num2str(acc2)]);
disp(['类别3的分类精度为:',num2str(acc3)]);
K最邻近密度估计技术是一种分类方法,不是聚类方法。
不是最优方法,实践中比较流行。
通俗但不一定易懂的规则是:
1.计算待分类数据和不同类中每一个数据的距离(欧氏或马氏)。
2.选出最小的前K数据个距离,这里用到选择排序法。
3.对比这前K个距离,找出K个数据中包含最多的是那个类的数据,即为待分类数据所在的类。
不通俗但严谨的规则是:
给定一个位置特征向量x和一种距离测量方法,于是有:
1.在N个训练向量外,不考虑类的标签来确定k邻近。在两类的情况下,k选为奇数,一般不是类M的倍数。
2.在K个样本之外,确定属于wi,i=1,2,...M类的向量的个数ki,显然sum(ki)=k。
3.x属于样本最大值ki的那一类wi。