使用accumarray输出矩阵

3

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比运行三次要快得多。这里我是否被卡住了?


或者您可以使用统计工具箱中的grpstats,或者如果您有许可证,可以使用图像处理工具箱中的regionprops - rahnema1
@rahnema1,min/mean/max 只是具体示例,以说明我的问题。 我实际用于 accumarray 的函数与 min/mean/max 完全不同,因此 grpstats 对我没有帮助。 我每天使用 regionprops,但我不知道您在描述什么。 - John
你可以使用 regionprops 找到区域的统计属性。用法:stats = regionprops(subs, vals,'MaxIntensity','MeanIntensity','MinIntensity')。由于你说实际的 accumarray 函数与 min/mean/max 很不同,因此 regionprops 也无法帮助到你。 - rahnema1
1个回答

4
你可以通过欺骗使匿名函数输出一个单元格数组而不是一个单一的值。这样,accumarray将给你一个矩阵的单元格数组。然后,当你完成时,你可以将所有的矩阵连接成一个单一的矩阵。请注意,你提出的匿名函数具有min、max和mean作为一行向量,但你期望的结果是一个向量。因此,在匿名函数内部我进行了转置。
我们需要考虑到的问题是填充值。你指定的填充值需要是一个标量。因此,你可以通过留空来欺骗,但是你的输出现在将包含单元格中的空矩阵,而不是用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{:} 会生成一个称为逗号分隔列表的内容,因此相当于将 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的工作原理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接