我能看到的最佳矢量化答案是:
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 计算导致 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
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')); %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 时间。