我需要在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循环遍历数组L
和V
来实现,但在Matlab中循环很慢,所以我一直在寻找更快的解决方案。有什么想法吗?
答案 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次。