matlab代码优化 - 聚类算法KFCG

时间:2013-07-18 17:35:56

标签: algorithm matlab optimization cluster-analysis

背景

我有一大组矢量(轴角表示中的方向数据......轴是矢量)。我想应用聚类算法。我尝试了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

1 个答案:

答案 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