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

Giu*_*ppe 2 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]
Run Code Online (Sandbox Code Playgroud)

然后,输出数组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)
Run Code Online (Sandbox Code Playgroud)

这可以通过遍历数组LVfor循环来实现,但在Matlab中循环很慢,所以我一直在寻找更快的解决方案.任何的想法?

Lui*_*ndo 6

这是一项标准工作accumarray.

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

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

整数标签

你可以使用

S = accumarray(L(:), V(:), [], @max).';
Run Code Online (Sandbox Code Playgroud)

在你的例子中,这给出了

>> 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
Run Code Online (Sandbox Code Playgroud)

整数标签,指定填充值

如果有整数之间的缝隙L,上面会给出一个0为不存在的标签结果.如果要更改该填充值(例如,更改NaN),请在以下位置使用第五个输入参数acccumarray:

S = accumarray(L(:), V(:), [], @max, NaN).';
Run Code Online (Sandbox Code Playgroud)

例:

>> 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

例:

>> 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
Run Code Online (Sandbox Code Playgroud)