我有一大组矢量(轴角表示中的方向数据......轴是矢量)。我想应用聚类算法。我尝试了kmeans,但计算时间太长(从未完成)。所以相反,我试图实现更快的KFCG算法(Kirke 2010):
最初,我们有一个集群,其中包含整个训练向量,而代码向量C1则是质心。在算法的第一次迭代中,通过将训练向量Xi的第一元素与代码向量C1的第一元素进行比较来形成聚类。如果xi1
我不确定什么比率适合码本,但它对于代码优化无关紧要。另请注意,我的是3-D,因此第3维也是如此。
我尝试将上述算法应用到Matlab 2013(学生版)中。这是我尝试过的一些不同的结构 - 但是花了太长时间(从未见过它):
%training vectors:
Atgood = Nx4 vector (see test data below if want to test);
vecA = Atgood(:,1:3);
roA = size(vecA,1);
%Codebook size, Nsel, is ratio of data
remainFrac2=0.5;
Nseltemp = remainFrac2*roA; %codebook size
%Ensure selected size after nearest power of 2 is NOT greater than roA
if 2^round(log2(Nseltemp)) < roA
NselIter = round(log2(Nseltemp));
else
NselIter = ceil(log2(Nseltemp)-1);
end
Nsel = 2^NselIter; %power of 2 - for LGB and other algorithms
主要优化块:
%KFCG:
%%cluster = cell(1,Nsel); %Unsure #rows - Don't know how to initialize if need mean...
codevec(1,1:3) = mean(vecA,1);
count1=1;
count2=1;
ind=1;
for kk = 1:NselIter
hh2 = 1:2:size(codevec,1)*2;
for hh1 = 1:length(hh2)
hh=hh2(hh1);
% for ii = 1:roA
% if vecA(ii,ind) < codevec(hh1,ind)
% cluster{1,hh}(count1,1:4) = Atgood(ii,:); %want all 4 elements
% count1=count1+1;
% else
% cluster{1,hh+1}(count2,1:4) = Atgood(ii,:); %want all 4
% count2=count2+1;
% end
% end
%EDIT: My ATTEMPT at optimizing above for loop:
repcv=repmat(codevec(hh1,ind),[size(vecA,1),1]);
splitind = vecA(:,ind)>=repcv;
splitind2 = vecA(:,ind)<repcv;
cluster{1,hh}=vecA(splitind,:);
cluster{1,hh+1}=vecA(splitind2,:);
end
clear codevec
%Only mean the 1x3 vector portion of the cluster - for centroid
codevec = cell2mat((cellfun(@(x) mean(x(:,1:3),1),cluster,'UniformOutput',false))');
if ind < 3
ind = ind+1;
else
ind=1;
end
end
if length(codevec) ~= Nsel
warning('codevec ~= Nsel');
end
或者,我认为3D矩阵会更快,而不是细胞?我试过但是使用我的方法在每次迭代时附加下一行(temp=[]; for...temp=[temp;new];
)
另外,我不确定什么是最好循环,for或while:
%If initialize cell to full length
while length(find(~cellfun('isempty',cluster))) < Nsel
好吧,不管怎样,第一种方法对我来说最快。
逻辑标准是什么?不是因为它与所描述的算法相匹配,而是从编码的角度来看,我使用的任何奇怪的方法(特别是那些多个内部循环)会减慢它的速度?我在哪里可以加快(您可以指出我的资源或以前的问题)?
我的数组大小Atgood为1,000,000x4 NselIter=19;
- 我是否只需要找到减小此大小的方法或者可以优化代码?
是否应该在CodeReview上询问?如果是这样,我会移动它。
以下是您可以用来测试的一些随机向量:
for ii=1:1000 %My size is ~ 1,000,000
omega = 2*rand(3,1)-1;
omega = (omega/norm(omega))';
Atgood(ii,1:4) = [omega,57];
end
答案 0 :(得分:1)
你最大的问题是重复遍历所有vecA FOR EACH CODEVECTOR,而不仅仅是那些属于相应集群的那些。你应该在它的代码向量上拆分每个集群。实际上,您的集群结构会增长和增长,每次迭代都会处理越来越多的样本。
您的第二个问题是围绕比较的循环,以及附加样本以构建群集。这两个都可以通过矢量化比较操作来解决。哦,我刚看到你的编辑,这是优化的。好多了。但是codevec(hh1,ind)
只是一个标量,所以你甚至不需要重新匹配。
试试这个版本:
% (preallocs added in edit)
cluster = cell(1,Nsel);
codevec = zeros(Nsel, 3);
codevec(1,:) = mean(Atgood(:,1:3),1);
cluster{1} = Atgood;
nClusters = 1;
ind = 1;
while nClusters < Nsel
for c = 1:nClusters
lower_cluster_logical = cluster{c}(:,ind) < codevec(c,ind);
cluster{nClusters+c} = cluster{c}(~lower_cluster_logical,:);
cluster{c} = cluster{c}(lower_cluster_logical,:);
codevec(c,:) = mean(cluster{c}(:,1:3), 1);
codevec(nClusters+c,:) = mean(cluster{nClusters+c}(:,1:3), 1);
end
ind = rem(ind,3) + 1;
nClusters = nClusters*2;
end