【问题标题】:What is a fast way to group values by index?按索引对值进行分组的快速方法是什么?
【发布时间】:2013-03-23 15:21:50
【问题描述】:

我有一个索引数组 I 和值 X,并且想要创建一个元胞数组 C,因此 C{i} = X(I==i)。计算 C 的最快和最佳方法是什么?

最直接的方法是为 I 中的所有唯一 i 评估 C{i} = X(I==i)(方法 1):

for i = unique(I)
    C{i} = X(I == i);
end

另一种天真的方法是遍历 I 中的所有 i 并将相应的 x 附加到 C(方法 2):

C = cellfun(@(x)(zeros(1,0)),cell(1,max(indices)),'UniformOutput',false);
for j = 1:length(I)
    i = I(j);
    C{i} = cat(2,C{i},X(j));
end

这两种方法都不是很快。为了进行基准测试,让我们生成一些测试数据:

I = floor(rand(1,N)*M)+1;
X = rand(1,N);

使用N = 1000000, M = 1000 两种方法采用:

  • 方法 1:4.79 秒
  • 方法 2:11.1 秒

在这里,方法 1 是最好的(仍然很慢)。将问题的参数更改为N = 1000000, M = 10000 会显着改变:

  • 方法 1:48.5 秒
  • 方法 2:10.3 秒

基本上,这两种方法都太慢了几个数量级。评估 C 的最佳方法是什么?

编辑: 正确答案显然是 Jonas 的下面。我附上基准测试结果以供参考。与上述方法相比,C 中元素的顺序不同。除此之外,以下给出相同的输出:

C = accumarray(I',X,[],@(x){x'})';
  • N = 100000, M = 1000:0.0397 秒
  • N = 100000, M = 10000:0.145 秒

【问题讨论】:

  • 请注意,为了更好地比较速度,您应该将C 预先分配为C = cell(max(indices),1);
  • 是的,我确实这样做了,但为了清楚起见,将其省略了。在这些情况下,它对运行时间没有显着影响。

标签: matlab


【解决方案1】:

最快的编写方式(也很可能是最快的运行方式)是accumarray

C = accumarray(I,X,[],@(x){x});

【讨论】:

  • 谢谢。 accumarray 似乎对大量应用程序非常有用。但通常对于 Matlab:他们不是优化语言以使惯用方式快速,而是添加特殊情况函数。对于 Matlab 来说,识别上述第一种方法的结构并像 accumarray 一样评估它并不难(它实际上完美地代表了它的结构)。
  • @digitalvision:Matlab 中的“惯用方式”不涉及循环。相反,它要么是矩阵运算,要么是专门的函数。是的,一旦你掌握了窍门,acumarray 就非常有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 2015-06-14
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
相关资源
最近更新 更多