从最大/最小accumarray指数(Index from accumarray with max/

2019-07-21 17:54发布

我有相同大小的矢量和单元阵列(具有重复字符串)。 单元阵列限定的基团。 我想找到在每个组的矢量最小值/最大值。

例如:

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

有任何想法吗? 这是没有必要使用accumarray但是我正在寻找快速矢量解决方案。

Answer 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时间。 (请注意,所有的抽动/滴答时刻是从在一个文件中定义的函数的第二次运行,以避免一次性的pcode代。)

添加“量化”(真arrayfun )一行的gridx计算导致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 /滴答时间。



Answer 2:

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

  • 定义下面的函数(在一个.m文件)

      function i=argmax(x) [~,i]=max(x); end 
  • 然后你可以找到最大的位置作为

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

      grvalue = value(gridx); 

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



文章来源: Index from accumarray with max/min