将具有相同ID的元素分组并查找最大值及其位置

Eln*_*naz 4 arrays matlab grouping vectorization

我有两个长度为16的向量.第一个,r例如:

r = [1;3;5;7;1;3;6;7;9;11;13;16;9;11;13;16];
Run Code Online (Sandbox Code Playgroud)

r包含ID列表.我想收集重复ID的索引,r以便每个组都是一个ID的索引列表.然后,我将使用这些索引访问第二个向量,a并找到每个组的索引上的最大值.

因此,我想产生使用输出向量ra,使得:

max(a(1),a(5)), max(a(2),a(6)), a(3), a(7), max(a(4),a(8)), max(a(9),a(13)), max(a(10),a(14)), max(a(11),a(15)), max(a(12),a(16))
Run Code Online (Sandbox Code Playgroud)

我还想保留最大值的索引.如何在MATLAB中有效地实现它?

ray*_*ica 6

您可以使用第三个输出unique分配r唯一ID中的每个唯一编号.然后,您可以将所有共享相同ID的数字与一个accumarray调用相关联,其中键是唯一ID,值是a此唯一ID数组中键的相应位置的实际值.收集所有这些值后,请使用accumarray以便您可以为每个唯一值使用这些值r来引用a和选择最大元素:

%// Define r and a
r = [1;3;5;7;1;3;6;7;9;11;13;16;9;11;13;16];
a = [...];

%// Relevant code
[~,~,id] = unique(r, 'stable');
out = accumarray(id(:), a(:), [], @max);
Run Code Online (Sandbox Code Playgroud)

'stable'unique因为我们希望出现的顺序分配唯一的ID是很重要的.不这样做会在分配ID之前先对值进行排序r,这不是我们想要的.

这是一个简单的例子.让我设置你的问题,生成一个随机的16元素数组存储a,你在其中尝试最终索引.我们还将建立r:

rng(123);
a = rand(16,1);
r = [1;3;5;7;1;3;6;7;9;11;13;16;9;11;13;16];
Run Code Online (Sandbox Code Playgroud)

这是a看起来像:

>> a

a =

    0.6965
    0.2861
    0.2269
    0.5513
    0.7195
    0.4231
    0.9808
    0.6848
    0.4809
    0.3921
    0.3432
    0.7290
    0.4386
    0.0597
    0.3980
    0.7380
Run Code Online (Sandbox Code Playgroud)

完成代码后,我们得到这个:

out =

    0.7195
    0.4231
    0.2269
    0.6848
    0.9808
    0.4809
    0.3921
    0.3980
    0.7380
Run Code Online (Sandbox Code Playgroud)

您可以自己验证这会给出正确的结果.具体而言,第一元素是最大的a(1)并且a(5)其是0.6965和0.7195分别与最大为0.7195.类似地,第二元件是最大a(2)a(6),其是0.2861和0.4231,最大为0.4231等等.


如果您还想记住索引用于选择最大元素,那么这将稍微复杂一些.您需要做的是accumarray再次调用,但值不是a实际索引值的值.您将使用第二个输出max来获取所选值的实际位置.但是,根据性质max,我们不能只是在max没有显式调用双输出版本的情况下抓住第二个元素max(我真的希望有另一种解决方法...... Python在NumPy中有一个函数调用numpy.argmax),这可以不能正确封装在匿名函数(即@(x) ...)中,因此您需要创建一个自定义函数来执行此操作.

创建一个名为的新函数maxmod并将其保存到一个名为的文件中maxmod.m.你把它放在函数中:

function p = maxmod(vals, ind)
    [~,ii] = max(vals(ind));
    p = ind(ii);
Run Code Online (Sandbox Code Playgroud)

这需要一个数组和一系列索引来访问数组,称为vals.然后我们找到这些选定结果的最大值,然后返回哪个索引给了我们最大值.

之后,你会这样打电话accumarray:

%// Define r and a
r = [1;3;5;7;1;3;6;7;9;11;13;16;9;11;13;16];
a = [...];

%// Relevant code
[~,~,id] = unique(r, 'stable');
out = accumarray(id(:), (1:numel(r)).', [], @(x) maxmod(a,x));
Run Code Online (Sandbox Code Playgroud)

这就是我现在得到的:

>> out

out =

     5
     6
     3
     8
     7
     9
    10
    15
    16
Run Code Online (Sandbox Code Playgroud)

如果查看每个值,这将反映a我们选择的哪个位置对应于每个组的最大值.