我有相同大小的矢量和单元阵列(具有重复字符串)。 单元阵列限定的基团。 我想找到在每个组的矢量最小值/最大值。
例如:
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但是我正在寻找快速矢量解决方案。
最好的矢量答案,我可以看到的是:
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 /滴答时间。