【问题标题】:Grouping elements with the same ID and finding the maximum value as well as its location对具有相同 ID 的元素进行分组并找到最大值及其位置
【发布时间】:2016-01-18 05:51:06
【问题描述】:

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

r = [1;3;5;7;1;3;6;7;9;11;13;16;9;11;13;16];

r 包含一个 ID 列表。我想在r 中收集重复 ID 的索引,以便每个组都是一个 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))

我还想保留最大值的索引。如何在 MATLAB 中有效地实现这一点?

【问题讨论】:

    标签: arrays matlab grouping vectorization


    【解决方案1】:

    您可以使用unique 的第三个输出为r 中的每个唯一编号分配唯一ID。然后,您可以使用 accumarray 调用将所有共享相同 ID 的数字分箱,其中键是唯一 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);
    

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

    这是一个简单的例子。让我来设置您的问题,即生成一个存储在您试图最终索引的a 中的随机 16 元素数组。我们还将设置r

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

    这是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
    

    运行代码后,我们得到:

    out =
    
        0.7195
        0.4231
        0.2269
        0.6848
        0.9808
        0.4809
        0.3921
        0.3980
        0.7380
    

    您可以自己验证这是否给出了正确的结果。具体来说,第一个元素是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);
    

    这需要一个数组和一系列索引来访问该数组,称为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));
    

    这就是我现在得到的:

    >> out
    
    out =
    
         5
         6
         3
         8
         7
         9
        10
        15
        16
    

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

    【讨论】:

    • 为什么不out = accumarray(id(:), a(:), [], @max)
    • @LuisMendo - 哈哈!是的!当然更容易阅读。我最初有一个 accumarray 调用来对索引进行分组,然后 cellfun 将最大值应用于每个组......然后我意识到我可以摆脱 cellfun.... 但后来我忘了删除这个事实我们不再需要使用索引。只需直接使用a。谢谢!
    • @rayryeng 谢谢!这行得通。您能否还解释一下如何使所选元素的索引与我们不取最大值的索引一起保持最大值。在您的示例中,我需要保留: 5, 6, 3, ...
    • @Elnaz 是的...你需要再打一个accumarray 电话。我会更新我的答案。
    • @rayryeng 不,谢谢你的帮助!
    猜你喜欢
    • 2020-07-06
    • 2023-03-26
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    • 2017-06-02
    相关资源
    最近更新 更多