我有一个矢量和一个大小相同的单元格数组(带有重复的字符串)。单元阵列定义组。我想在每个组的向量中找到最小/最大值。
例如:
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,但我正在寻找快速矢量化解决方案。
答案 0 :(得分: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秒的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秒的抽动/抽动时间。
答案 1 :(得分:1)
当遇到类似的问题*时,我提出了这个解决方案:
定义以下函数(在.m文件中)
function i=argmax(x)
[~,i]=max(x);
end
然后您可以找到最大位置
gridx = accumarray(grnum,grnum,[],@(i)i(argmax(value(i))) );
,最大值为
grvalue = value(gridx);
(*如果我正确理解你的问题)