【问题标题】:MATLAB: accumarray with matrix as values (second input parameter)MATLAB:以矩阵为值的 accumarray(第二个输入参数)
【发布时间】:2018-05-12 23:02:24
【问题描述】:

我有一个包含百分比值的矩阵,其中每一行代表一个单独的观察值。我需要计算这些值对应于相同下标的累积乘积。我尝试使用accumarray 函数,只要我使用列向量作为值(而不是矩阵),它就可以正常工作并且符合预期。 我想知道在不遍历值矩阵的各个列的情况下解决我的问题的最佳方法是什么?

这是我的示例代码:

subs = [1;1;1;2;2;2;2;2;3;3;4;4;4];
vals1 = [0.1;0.05;0.2;0.02;0.09;0.3;0.01;0.21;0.12;0.06;0.08;0.12;0.05];

% This is working as expected
result1 = accumarray(subs,vals1, [], @(x) prod(1+x) -1)


vals2 = [vals1,vals1];

% This is not working as the second input parameter of accumarray
% apperently must be a vector (rather than a matrix)
result2 = accumarray(subs, vals2, [], @(x) prod(1+x) -1)

【问题讨论】:

    标签: matlab matrix accumarray


    【解决方案1】:

    对于 val,您可以将其设置为 1:size(vals2,1) 并使用它来提取 vals2 的行。该函数还需要返回单元格。

    result2 = accumarray(subs, 1:size(vals2,1), [], @(x) {prod(1+vals2(x,:),1)-1})
    

    您可以连接单元格元素:

    result3 = vertcat(result2{:})
    

    或者全部在一行中:

    result3 = cell2mat( accumarray(subs, 1:size(vals2,1), [], @(x) {prod(1+vals2(x,:),1)-1}))
    
    result3 =
    
       0.38600   0.38600
       0.76635   0.76635
       0.18720   0.18720
       0.27008   0.27008
    

    使用[10000 x 200] 矩阵作为输入比较三种建议方法的 Octave 测试结果:

    subs = randi(1000,10000,1);
    vals2 = rand(10000,200);
    
    =========CELL2MAT========
    Elapsed time is 0.130961 seconds.
    =========NDGRID========
    Elapsed time is 3.96383 seconds.
    =========FOR LOOP========
    Elapsed time is 6.16265 seconds.
    

    Online Demo

    【讨论】:

    • 这看起来不是一个简单的解决方案。它正在工作,但恕我直言,它使 accumarray 函数的可读性降低。在这种情况下,我认为我更喜欢简单的 for 循环解决方案。
      for i = 1 : size(vals2, 2)result2(:,i) = accumarray(subs, vals2(:,i), [], @(x) prod(1+x) -1);end
    • 列数较多时,for-loop 解决方案可能效率低下。
    • 嗯,就我而言,列数可以高达 10,000。
    • @rahnema1 我认为OP发布的for循环解决方案效率不高。我在没有 accumarray 的情况下实现了一个改进的 for 循环,它的执行速度与 cell2mat 一样快。我修改了您的脚本并添加了改进的 for 循环解决方案。运行它几次,你会看到性能类似于 cell2mat。 rextester.com/RLYKA32361 。老实说,我对简单的 for 循环匹配 accumarray 感到有点惊讶。如果我遗漏了什么,请告诉我。
    • @Turbo Here 我编辑了代码并为subs 使用了随机数据集。有 1500 唯一类别,每个类别最多重复 500 次。我注释掉了ndgrid,因为它需要大量内存。改进后的循环比未改进的循环好,但它不能胜过cell2mat。最好使用repelem 创建数据集,但该版本的 Octave 不包含repelem
    【解决方案2】:

    您需要向subs 添加第二组下标(使其为 N×2)来处理您的 2D 数据,该数据仍必须作为 N 元素向量(即一个元素用于subs 中的每一行)。您可以使用ndgrid 生成一组新的二维下标:

    [subs1, subs2] = ndgrid(subs, 1:size(vals2, 2));
    result2 = accumarray([subs1(:) subs2(:)], vals2(:), [], @(x) prod(1+x) -1)
    

    以及您的示例数据的结果:

    result2 =
    
        0.3860    0.3860
        0.7664    0.7664
        0.1872    0.1872
        0.2701    0.2701
    

    【讨论】:

    • 如果vals2 中的列数是可变的,您将如何定义ngrid 的输出参数?
    • @Andi:这正是我在上面的代码中所做的。注意ndgrid 的第二个参数是一个从 1 到size(vals2, 2) 的向量(即vals2 中的列数)。
    猜你喜欢
    • 1970-01-01
    • 2015-07-31
    • 2017-08-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多