前记
最近在做人脸识别毕业设计,用到模糊KNN算法(FuzzyKNN,FKNN)。FKNN是在KNN基础上发展而来,上网搜寻博客缺乏该算法的资料,等有空写一篇该算法的详细介绍。本篇使用Matlab简单地实现KNN(未实现Kd-Tree算法)主要针对科研工作。
代码实现
function y = knn(x, x_train, y_train, K)
% KNN K-Nearest Neighbors Algorithm
% Input: x: 待分类预测点集
% x_train: 训练点集
% y_train: 训练点集标类
% K: K值
%
% Output: y: 待分类预测点集标类
%
% Author: Keyven_guo
[size_x,~] = size(x); % 确定有多少个待分类预测点,不管这些点的特征维度
predicted_label = zeros(size_x,1); % 产生矩阵Matrix[size_x][1]并铺0
for i = 1:size_x
[dist,neighbors] = top_K_neighbors(x_train,x(i,:),K);
% x(i,:)表示取矩阵x的第i行,:代表全部
predicted_label(i) = keyclass(y_train(neighbors),max(y_train(neighbors));
% y_train(neighbors)表示取下标∈neighbors的y_train元素
end
y = predicted_label;
end
function [dist, neighbors] = top_K_neighbors(x_train, y_train, x, K)
% Input: x_train: 训练点集
% y_train: 训练点集标类
% x: 待分类预测点
% K: K值
%
% Output: dist: K个邻居距x的距离(升序排序)
% neighbors: K个邻居的原下标
%
% Author: Keyven_guo
[size_x,~] = size(x_train);
test_mat = repmat(x,size_x,1); % 产生矩阵Matrix[size_x][1]并将值设为x
% 本例产生一个与x_train大小一样的矩阵,每一行为x的特征向量
dist_mat = (x_train-double(test_mat)).^2; % 欧式距离
dist_array = sum(dist_mat'); % 对dist_mat转置('表示转置矩阵)后使用sum函数,注意sum函数是对列求和
[dists,neighbors] = sort(dist_arry); % 对dist_arry排序并用neighbors记录下标的变化情况
dists = dists(1:K); % 取前k小
neighbors = neighbors(1:K);
end
function result = keyclass(k_labels, class_num)
% 类个数比较少,不想用map,直接用Hash数组来统计
%
% Author: Keyven_guo
k = size(k_labels);
class_count = zeros(1,class_num);
for i=1:k
class_index = k_labels(i) + 1;
class_count(class_index) = class_count(class_index) + 1;
end
result = max(class_count);
result = result - 1;
end
后记
实际开发中,如果不使用Kd-Tree的话,上述K近邻算法可以使用以下算法改进:
(1) ACM算法题中的寻找前k小元素(最大堆思路,适合海量数据处理,空间复杂度小,时间复杂度接近O(n);
(2) 数据结构Map