3

MATLABaccumarray在许多应用程序中的强大功能令人难以置信。我的问题是,我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

我想我可以只运行accumarray3 次,但我的功能很慢,运行accumarray一次会比运行 3 次快得多。我只是在这里冲洗吗?

4

1 回答 1

4

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

我们必须考虑的问题是填充值。您指定的填充值必须是标量。因此,您可以通过忽略它来作弊,但是您的输出现在将在单元格中包含空矩阵,而不是结果的行被填充为 0。解决此问题的一种方法是找到所有为空的单元格,将它们替换为一行零,然后在完成后将它们拼凑在一起。要确定输出的哪些行将accumarray是空的,您可以使用cellfuncombine withisempty以便我们可以看到结果中的哪些元素是空的。一个更简洁的方法是首先预先分配一个矩阵,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{:});

注意catwhich 的使用是在指定维度中将矩阵连接在一起。这样做out{:}会产生所谓的逗号分隔列表,因此它相当于获取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

但是,如果我可以说实话 - 如果您确定您将只有三个值 bin into accumarray,那么简单地调用它三次然后在完成后连接所有内容可能会更快。我认为它更具可读性,并且可以非常清楚地说明您在做什么。像我对上面的单元格数组所做的那样,需要您真正了解 MATLAB 的工作原理。

于 2017-03-10T17:13:25.180 回答