我能看到的最好的向量化答案是:
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秒的tic/toc时间。(注意,所有的tic/tock时间都来自于运行函数的第二次,以避免一次性pcode生成。)
添加“向量化”(实际上是
arrayfun
)一行
gridx
计算会导致0.975秒的tic/toc时间。不错,进一步调查表明,大部分时间都被
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
计时器 tic/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'));
tic
[grnum, grname] = grp2idx(groupValues);
grname = num2cell(char(str2double(grname)));
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秒的滴答声/嘀嗒声时间。