我正在使用Matlab中的k-最近邻算法进行数据分析。我的数据由大约11795 x 88数据矩阵组成,其中行是观察值,列是变量。
我的任务是为n个选定的测试点找到k-最近邻居。目前我正在使用以下逻辑:
对于所有测试点
LOOP all the data and find the k-closest neighbors (by euclidean distance)
换句话说,我循环所有n个测试点。对于每个测试点,我按照欧几里德距离搜索k-最近邻居的数据(不包括测试点本身)。对于每个测试点,这需要大约k×11794次迭代。因此整个过程需要大约n x k x 11794次迭代。如果n = 10000且k = 7,则这将是大约825,600次迭代。
是否有更有效的方法来计算k-最近邻居?现在大多数计算都会浪费,因为我的算法很简单:
计算到所有其他点的欧氏距离,拾取最接近的点并排除距离进一步考虑的最近点 - >计算到所有其他点的欧氏距离并拾取最接近的 - >等等 - >等。
有没有一种明智的方法可以摆脱这种“浪费计算”?
目前这个过程大约需要7个小时在我的电脑上(3.2 GHz,8 GB RAM,64位Win 7)...... :(
以下是一些明确说明的逻辑(这不是我的所有代码,但这是消耗性能的部分):
for i = 1:size(testpoints, 1) % Loop all the test points
neighborcandidates = all_data_excluding_testpoints; % Use the rest of the data excluding the test points in search of the k-nearest neighbors
testpoint = testpoints(i, :); % This is the test point for which we find k-nearest neighbors
kneighbors = []; % Store the k-nearest neighbors here.
for j = 1:k % Find k-nearest neighbors
bdist = Inf; % The distance of the closest neighbor
bind = 0; % The index of the closest neighbor
for n = 1:size(neighborcandidates, 1) % Loop all the candidates
if pdist([testpoint; neighborcandidates(n, :)]) < bdist % Check the euclidean distance
bdist = pdist([testpoint; neighborcandidates(n, :)]); % Update the best distance so far
bind = n; % Save the best found index so far
end
end
kneighbors = [kneighbors; neighborcandidates(bind, :)]; % Save the found neighbour
neighborcandidates(bind, :) = []; % Remove the neighbor from further consideration
end
end
答案 0 :(得分:3)
使用pdist2
:
A = rand(20,5); %// This is your 11795 x 88
B = A([1, 12, 4, 8], :); %// This is your n-by-88 subset, i.e. n=4 in this case
n = size(B,1);
D = pdist2(A,B);
[~, ind] = sort(D);
kneighbours = ind(2:2+k, :);
现在,您可以使用kneighbours
为A
中的行编制索引。请注意,kneighbours
的列对应于B
但是,由于您已经使用pdist
进入统计工具箱,为什么不使用Matlab的knnsearch
?
kneighbours_matlab = knnsearch(A,B,'K',k+1);
请注意kneighbours
与kneighbours_matlab(:,2:end)'
答案 1 :(得分:1)
我不熟悉特定的matlab函数,但您可以从公式中删除k。
有一个众所周知的选择算法
e.g。
A=2,4,6,8,10,1,3,5,7,9; k=5
output = 2,4,1,3,5,10,6,8,7,9
这是在O(n)步骤中完成的,并不依赖于k。
EDIT1:您还可以预先计算所有距离,因为它看起来就像您花费大部分计算的地方一样。它将是一个大约800M矩阵,因此不应该是现代机器上的问题。
答案 2 :(得分:1)
我不确定它是否会加速代码,但它会删除内部的两个循环
for i = 1:size(testpoints, 1) % //Loop all the test points
temp = repmat(testpoints(i,:),size(neighborcandidates, 1),1);
euclead_dist = (sum((temp - neighborcandidates).^2,2).^(0.5));
[sort_dist ind] = sort(euclead_dist);
lowest_k_ind = ind(1:k);
kneighbors = neighborcandidates(lowest_k_ind, :);
neighborcandidates(lowest_k_ind, :) = [];
end
答案 3 :(得分:1)
这不会起作用吗?
adjk = adj;
for i=1:k-1
adj_k = adj_k*adj;
end
kneigh = find(adj_k(n,:)>0)
给定节点n和索引k?
答案 4 :(得分:0)
在Matlab的上下文中,这可能是一个更快的代码。您还可以尝试并行函数,数据索引和近似最近邻算法,从理论上讲更有效。
% a slightly faster way to find k nearest neighbors in matlab
% find neighbors for data Y from data X
m=size(X,1);
n=size(Y,1);
IDXs_out=zeros(n,k);
distM=(repmat(X(:,1),1,n)-repmat(Y(:,1)',m,1)).^2;
for d=2:size(Y,2)
distM=distM+(repmat(X(:,d),1,n)-repmat(Y(:,d)',m,1)).^2;
end
distM=sqrt(distM);
for i=1:k
[~,idx]=min(distM,[],1);
id=sub2ind(size(distM),idx',(1:n)');
distM(id)=inf;
IDXs_out(:,i)=idx';
end