在实验中经常会需要计算K近邻,为了避免多次重写,这里用MATLAB实现了一个计算K近邻的函数,该函数要求输入两个参数,第一个参数就是数据矩阵,要求每行为一个多维样本点,第二个参数就是K值了。函数返回K近邻矩阵。计算K近邻比较好的一种算法是利用KD树,这里暂且用的是易于理解的常规方法。使用KD树的代码将来补充。
具体代码实现如下
function [ Result ] = KNN( Data,k )
%计算K近邻的一个通用函数
%要求一行为一个多维变量
%返回Result为一个矩阵,第i行为到第i个数据点的欧几里得距离最短的k个数据点序号的排列,列序数越小距离越近
%计算KNN用KD树要更好一点,这个第一版暂时先用普通方法了
datasize = size(Data);
Distance = zeros(datasize(1),datasize(1));%距离矩阵,存放两点之间的距离
%%%%
% 计算距离矩阵
%
%%%%
for i = 1:datasize(1)-1
for j = i+1:datasize(1)
tempsum = 0;
for ci = 1:datasize(2)
tempsum = tempsum + (Data(i,ci)-Data(j,ci))*(Data(i,ci)-Data(j,ci));
end
Distance(i,j) = sqrt(tempsum);
Distance(j,i) = sqrt(tempsum);
end
end
Result = zeros(datasize(1),k);%结果矩阵
%%%%
% 计算结果矩阵
%
%%%%
for i = 1:datasize(1)
for j = 1:datasize(1)
if i==j
continue;
end
index = k;
while index>0 && Result(i,index)==0
index = index-1;
end
if index == 0
Result(i,1) = j;
else
if Distance(i,j)<Distance(i,Result(i,index))
while index>0 && Distance(i,j)<Distance(i,Result(i,index))
temp = Result(i,index);
Result(i,index) = j;
if index<k
Result(i,index+1) = temp;
end
index = index-1;
end
else
if index<k
Result(i,index+1) = j;
end
end
end
end
end
end
使用的测试代码如下所示
clc,clear
load('Wine.mat')
Data = Wine(:,2:14);
Result = KNN(Data,10)
计算结果如下所示
测试使用的是加州大学欧文分校的机器学习测试数据集中的Wine数据集,下载地址是http://archive.ics.uci.edu/ml/datasets/Wine ,也可以从百度网盘链接链接:https://pan.baidu.com/s/1jKowB8E 密码:xift下载MATLAB的mat文件。
另外上面的测试方法其实是不太好的,最好是先将数据normlize一下。
计算一个向量v在数据集矩阵Data中的K近邻代码:
function [ Result ] = vKNN( v,Data,k )
% 对一个向量量v计算它在Data中的k近邻
% v是那个向量,Data是数据集矩阵,k为近邻数
% 要求向量是一个行向量
datasize = size(Data);
Result = zeros(1,k);%结果向量
Distance = zeros(datasize(1),1);%距离矩阵
%距离矩阵计算
for i = 1:datasize(1)
tempsum = 0;
for j = 1:datasize(2)
tempsum = tempsum + (Data(i,j)-v(j))*(Data(i,j)-v(j));
end
Distance(i) = sqrt(tempsum);
end
for j = 1:datasize(1)
index = k;
while index>0 && Result(index)==0
index = index-1;
end
if index == 0
Result(1) = j;
else
if Distance(j)<Distance(Result(index))
while index>0 && Distance(j)<Distance(Result(index))
temp = Result(index);
Result(index) = j;
if index<k
Result(index+1) = temp;
end
index = index-1;
end
else
if index<k
Result(index+1) = j;
end
end
end
end
end
其实已经有一些人开发了一些在MATLAB中计算K近邻的工具箱,VLFeat就是一个例子,它实现了kmeans,KDTree等多种算法。其下载地址为http://www.vlfeat.org/download.html ,下载完成之后解压,在MATLAB命令行中运行其中的toolbox文件夹下的vl_setup.m即可完成该工具箱的配置,在MATLAB命令行中输入vl_version verbose,,命令如果结果显示类似下图,证明配置成功。
下面是一个使用VLFeat求K近邻的一个例子
clc,clear
X = rand(2,100);%一百个二维列向量
kdtree = vl_kdtreebuild(X);%构建kd树
Q = rand(2,1);
[index,distance] = vl_kdtreequery(kdtree, X, Q);%返回X中与Q最近的点
[index, distance] = vl_kdtreequery(kdtree, X, Q, 'NumNeighbors', 10) ;%返回X中Q的K的近邻
scatter(Q(1),Q(2),'p')
hold on
for i = 1:100
has = 0;
for j = 1:10
if index(j)==i
has = 1;
break;
end
end
if has==1
scatter(X(1,i),X(2,i),'o')
hold on
else
scatter(X(1,i),X(2,i),'.')
hold on
end
end