使用accumarray输出矩阵

时间:2017-03-10 16:59:17

标签: matlab matrix accumarray

MATLAB的accumarray在许多应用程序中都具有令人难以置信的强大功能。我的问题是,我的accumarray函数应用于我的输入有三个输出,而accumarray只能处理标量输出。例如,我想做这样的事情:

subs = [1;2;4;2;4;5];
vals = [1;1;1;2;5;1];
accumarray(subs, vals, [], @(x)[min(x),mean(x),max(x)],0)

并让accumarray返回:

1.0000    1.0000         0    1.0000    1.0000
1.0000    1.5000         0    3.0000    1.0000
1.0000    2.0000         0    5.0000    1.0000

我想我可以运行accumarray三次,但我的功能很慢,运行accumarray一次比运行三次要快得多。我刚才在这里?

1 个答案:

答案 0 :(得分:4)

您可以作弊使匿名函数输出单元格数组而不是单个值。这样,accumarray将为您提供矩阵的单元格数组。然后,您可以在完成后将所有矩阵连接到单个矩阵。请注意,您提议的匿名函数将minmaxmean作为行向量,但您的预期结果是向量。因此,我已将此转换为您的匿名函数。

我们必须考虑的问题是填充值。您指定的填充值必须是标量。因此,您可以通过将其留下来作弊,但是然后您的输出现在将包含单元格中的空矩阵,而不是结果的行被填充为0.解决此问题的方法是查找所有空单元格,将其替换为一排零,然后在你完成时将它们拼凑在一起。要确定accumarray输出的哪些行将为空,您可以将cellfunisempty结合使用,以便我们可以看到结果中的哪些元素为空。一种更简洁的方法是先预先分配一个zeros的矩阵,然后只填充与accumarray输出中非空位置相对应的行,以完成它:

subs = [1;2;4;2;4;5];
vals = [1;1;1;2;5;1];
out = accumarray(subs, vals, [], @(x){[min(x),mean(x),max(x)].'});
ind_empty = cellfun('isempty', out);
out_final = zeros(3, numel(out));
out_final(:, ~ind_empty) = cat(2, out{:});

注意使用cat,它在指定的维度上将矩阵连接在一起。执行out{:}会产生所谓的comma-separated list,因此它等同于获取accumarray输出的每一列并将它们作为单独的参数放入cat,这样我们最终会将所有列组合成一个矩阵,但我以这样的方式切入输出,我们只填充那些非空的位置。

使用您的测试输入,我匹配您所获得的:

>> out_final

out_final =

    1.0000    1.0000         0    1.0000    1.0000
    1.0000    1.5000         0    3.0000    1.0000
    1.0000    2.0000         0    5.0000    1.0000

但是,如果我可以说实话 - 如果你确定你只能将三个值合并到accumarray,那么简单地调用它三次然后连接一切可能会更快当你完成了。我认为它更具可读性,并且非常清楚你在做什么。按照上面对单元格数组的方式进行操作,需要您真正了解MATLAB的工作原理。