Matlab:避免for循环找到具有相同标签的值中的最大值 [英] Matlab: avoid for loops to find the maximum among values with same labels
问题描述
具体来说,我有一个数组 L
的标签和一个数组 V
的值,大小相同。我需要生成一个数组 S
,其中包含 L
的每个值的最大值 V
。一个例子会更好地解释:
pre $ 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的值将是:< (1)= 9(V(i)使得L(i)== 1是:5,4 (i)= 2,3(2),3(9)=> 9)
s(2)= 8 (3)= 7(使得L(i)= 3的值V(i)是:3,4,5,7-> max = 7 )
s(4)= 8(使得L(i)== 4的值V(i)是:6,7,8,6 - > max = 8)
这可以通过遍历数组 L
和 V
用for循环,但是在Matlab for循环中很慢,所以我正在寻找一个更快的解决方案。任何想法?
这是 accumarray
。
需要考虑三种情况,通用性越来越高:
$ b
- 整型标签
- 整型标签,请指定填充值。
- 清除间隙;或非整数标签。一般情况下。
整数标签
您可以使用
S = accumarray(L(:),V(:),[],@max)。
在你的例子中,这给出了
>> L = [1 1 1 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 中使用第五个输入参数。 code $:
$ $ $ $ $ $ $ $ $ $ $ $ $ S $ accumarray(L(:),V(:),[],@ NAN)'。
示例:
>> L = [1 1 1 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,NaN)'
S =
9 8 7 8 NaN NaN 6
清除间隙;或非整数标签。一般情况下
当整数标签之间的差距很大时,使用填充值可能是低效的。在这种情况下,您可能只想在 S
中取得没有填充值的有意义的值,即跳过不存在的标签。此外,可能是 L
不一定包含整数。
这两个问题可以通过应用 unique
code> ,然后使用 accumarray
:
[〜,〜,Li] =唯一(L); %//将L转换为连续的整数
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]; %//注意:非整数值
>> V = [5 4 3 2 1 2 3 4 5 6 7 8 9 8 7 6]; %//与你的例子相同
>> [〜,〜,Li] =唯一(L); %//将L转换为连续的整数
>> S $ accumarray(Li(:),V(:),[],@ max,NaN)。'
S =
9 5 8 7 8 6
I need to find the maximum among values with same labels, in matlab, and I am trying to avoid using for loops.
Specifically, I have an array L
of labels and an array V
of values, same size. I need to produce an array S
which contains, for each value of L
, the maximum value of V
. An example will explain better:
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]
Then, the values of the output array S will be:
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)
this can be trivially implemented by traversing the arrays L
and V
with a for loop, but in Matlab for loops are slow, so I was looking for a faster solution. Any idea?
This is a standard job for accumarray
.
Three cases need to be considered, with increasing generality:
- Integer labels.
- Integer labels, specify fill value.
- Remove gaps; or non-integer labels. General case.
Integer labels
You can just use
S = accumarray(L(:), V(:), [], @max).';
In your example, this gives
>> 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
Integer labels, specify fill value
If there are gaps between integers in L
, the above will give a 0
result for the non-existing labels. If you want to change that fill value (for example to NaN
), use a fifth input argument in acccumarray
:
S = accumarray(L(:), V(:), [], @max, NaN).';
Example:
>> 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
Remove gaps; or non-integer labels. General case
When the gaps between integer labels are large, using a fill value may be inefficient. In that case you may want to get only the meaningful values in S
, without fill values, i.e.skip non-existing labels. Also, it may be the case that L
doesn't necessarily contain integers.
These two issues are solved by applying unique
to the labels before using accumarray
:
[~, ~, Li] = unique(L); %// transform L into consecutive integers
S = accumarray(Li(:), V(:), [], @max, NaN).';
Example:
>> 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
这篇关于Matlab:避免for循环找到具有相同标签的值中的最大值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!