2013-03-15 54 views
3

我有一个向量和单元格阵列(与重复的字符串)具有相同的大小。单元格数组定义组。我想在每个组的向量中查找最小/最大值。准确的指数与最大/最小

例如:

value = randperm(5) %# just an example, non-unique in general 
value = 
    4  1  2  3  5 
group = {'a','b','a','c','b'}; 
[grnum, grname] = grp2idx(group); 

我使用ACCUMARRAY函数为这样:

grvalue = accumarray(grnum,value,[],@max); 

所以我有唯一的组名称(grname)和新的载体(grvalue)新单元阵列。

grname = 
    'a' 
    'b' 
    'c' 
grvalue = 
    4 
    5 
    3 

但我还需要找到已包含在新向量中的旧向量的值的位置索引。

gridx = 1 5 4 

任何想法?没有必要使用准系统,但我正在寻找快速矢量化解决方案。

+1

你使用哪种matlab版? – Jonas 2013-03-15 21:04:42

+0

@Jonas:2012b,Windows7 x64。 – yuk 2013-03-15 23:19:35

回答

1

最好的量化答案,我可以看到的是:

gridx = arrayfun(@(grix)find((grnum(:)==grix) & (value(:)==grvalue(grix)),1),unique(grnum)); 

,但我不能说这是一个“快”矢量化的解决方案。 arrayfun真的很有用,但通常不会比循环更快。


但是,最快的答案并不总是矢量化的。如果我重新实现代码,你写它,但有一个更大的数据集:

nValues = 1000000; 
value = floor(rand(nValues,1)*100000); 
group = num2cell(char(floor(rand(nValues,1)*4)+'a')); 
tic; 
[grnum, grname] = grp2idx(group); 
grvalue = accumarray(grnum,value,[],@max); 
toc; 

我的电脑给我的0.886秒抽动/ TOC时间。 (注意,所有tic/tock时间来自文件中定义的函数的第二次运行,以避免一次性生成pcode。)

添加“矢量化”(真的是arrayfun)一行gridx计算导致tic/tock时间为0.975秒。还不错,另外一项调查显示大部分时间都在拨打grp2idx电话。

如果我们重新实现这个作为一个非矢量化,简单的循环,包括gridx计算,像这样:

tic 
[grnum, grname] = grp2idx(group); 
grvalue = -inf*ones(size(grname)); 
gridx = zeros(size(grname)); 
for ixValue = 1:length(value) 
    tmpGrIdx = grnum(ixValue); 
    if value(ixValue) > grvalue(tmpGrIdx) 
     grvalue(tmpGrIdx) = value(ixValue); 
     gridx(tmpGrIdx) = ixValue; 
    end 
end 
toc 

抽动/ TOC时间约为0.847秒,稍微比原来的代码快。


采取这种有点进一步,大部分时间出现在细胞阵列的存储器访问丢失。例如:

tic; groupValues = double(cell2mat(group')); toc %Requires 0.754 seconds 
tic; dummy  =  (cell2mat(group')); toc %Requires 0.718 seconds 

如果您最初定义组名称为数字阵列(例如,我将使用groupValues正如我上面所定义它们),该时间减少了不少,甚至使用相同的代码:

groupValues = double(cell2mat(group')); %I'm assuming this is precomputed 
tic 
[grnum, grname] = grp2idx(groupValues); 
grname = num2cell(char(str2double(grname))); %Recapturing your original names 
grvalue = -inf*ones(size(grname)); 
gridx = zeros(size(grname)); 
for ixValue = 1:length(value) 
    tmpGrIdx = grnum(ixValue); 
    if value(ixValue) > grvalue(tmpGrIdx) 
     grvalue(tmpGrIdx) = value(ixValue); 
     gridx(tmpGrIdx) = ixValue; 
    end 
end 
toc 

这产生了0.16秒的tic/tock时间。

+0

谢谢,我会尝试你的代码。 – yuk 2013-03-15 21:09:54

1

当面对类似的问题*,我想出了这个解决方案:

  • 定义下列函数(在.m文件)

    function i=argmax(x) 
        [~,i]=max(x); 
        end 
    
  • 那么你就可以找到最大位置为

    gridx = accumarray(grnum,grnum,[],@(i)i(argmax(value(i)))); 
    
  • 和最大值为

    grvalue = value(gridx); 
    

(*如果我正确地理解您的问题)