Matlab:避免for循环在具有相同标签的值中找到最大值

时间:2014-08-21 10:34:28

标签: matlab for-loop labels

我需要在matlab中找到具有相同标签的值中的最大值,并且我试图避免使用for循环。

具体来说,我有一个数组L的标签和一个数组V的值,大小相同。我需要生成一个数组S,其中包含L的每个值,V的最大值。一个例子将更好地解释:

L = [1,1,1,2,2,2,3,3,3,4,4,4,1,2,3,4]

V = [5,4,3,2,1,2,3,4,5,6,7,8,9,8,7,6]

然后,输出数组S的值为:

s(1) = 9 (the values V(i) such that L(i) == 1 are: 5,4,3,9 -> max = 9)

s(2) = 8 (the values V(i) such that L(i) == 2 are: 2,1,2,8 -> max = 8)

s(3) = 7 (the values V(i) such that L(i) == 3 are: 3,4,5,7 -> max = 7)

s(4) = 8 (the values V(i) such that L(i) == 4 are: 6,7,8,6 -> max = 8)

这可以通过使用for循环遍历数组LV来实现,但在Matlab中循环很慢,所以我一直在寻找更快的解决方案。有什么想法吗?

2 个答案:

答案 0 :(得分:6)

这是accumarray的标准作业。

需要考虑三种情况,通用性越来越高:

  • 整数标签。
  • 整数标签,指定填充值。
  • 消除差距;或非整数标签。一般情况。

整数标签

你可以使用

S = accumarray(L(:), V(:), [], @max).';

在你的例子中,这给出了

>> L = [1 1 1 2 2 2 3 3 3 4 4 4 1 2 3 7];
>> V = [5 4 3 2 1 2 3 4 5 6 7 8 9 8 7 6];
>> S = accumarray(L(:), V(:), [], @max).'
S =
     9     8     7     8

整数标签,指定填充值

如果L中的整数之间存在间隔,则上述内容会为不存在的标签提供0结果。如果您要更改填充值(例如更改为NaN),请在acccumarray中使用第五个输入参数:

S = accumarray(L(:), V(:), [], @max, NaN).';

示例:

>> L = [1 1 1 2 2 2 3 3 3 4 4 4 1 2 3 7]; %// last element changed
>> V = [5 4 3 2 1 2 3 4 5 6 7 8 9 8 7 6]; %// same as in your example
>> S = accumarray(L(:), V(:), [], @max, NaN).'
S =
     9     8     7     8   NaN   NaN     6

消除差距;或非整数标签。一般情况

当整数标签之间的间隙很大时,使用填充值可能效率低下。在这种情况下,您可能希望仅在S中获取有意义的值,而不使用填充值,即跳过不存在的标签。此外,L 可能不一定包含整数

通过在使用accumarray之前将unique应用于标签来解决这两个问题:

[~, ~, Li] = unique(L); %// transform L into consecutive integers
S = accumarray(Li(:), V(:), [], @max, NaN).';

示例:

>> L = [1.5 1.5 1.5 2 2 2 3 3 3 4 4 4 1 2 3 7.8]; %// note: non-integer values
>> V = [5   4   3   2 1 2 3 4 5 6 7 8 9 8 7 6  ]; %// same as in your example
>> [~, ~, Li] = unique(L); %// transform L into consecutive integers
>> S = accumarray(Li(:), V(:), [], @max, NaN).'
S =
     9     5     8     7     8     6

答案 1 :(得分:4)

helper=[L.', V.'];
helper=sortrows(helper,-2);
[~,idx,~]=unique(helper(:,1));
S=helper(idx,2);

我所做的是:我将两个数组作为列加入。然后我将它们排在第二列,首先是最大元素。然后,在我从L返回相应的值之前,我在V中获取了唯一值的idx。

来自 Luis Mendo 的解决方案更快。但据我所知,如果L内有零,负值或非整数,他的解决方案不起作用:

Luis solution: Elapsed time is 0.722189 seconds.
My solution: Elapsed time is 2.575943 seconds.

我用过:

L= ceil(rand(1,500)*10);
V= ceil(rand(1,500)*250);

并运行代码10000次。