我正在尝试找到在Matlab(零均值,单位方差列)中标准化矩阵的最快方法。归结为这是对矩阵中的所有行应用相同操作的最快方法。我阅读的每篇文章都得出相同的结论:使用bsxfun而不是repmat
由Mathworks撰写的这篇文章是一个示例:http://blogs.mathworks.com/loren/2008/08/04/comparing-repmat-and-bsxfun-performance/

但是,在我自己的计算机上尝试此操作时,repmat总是更快。这是使用与文章相同的代码得到的结果:

m = 1e5;
n = 100;
A = rand(m,n);

frepmat = @() A - repmat(mean(A),size(A,1),1);
timeit(frepmat)

fbsxfun = @() bsxfun(@minus,A,mean(A));
timeit(fbsxfun)

结果:
ans =

    0.0349


ans =

    0.0391

实际上,无论输入矩阵有多大,在这种情况下我都无法使bsxfun的性能优于repmat。

有人可以解释吗?

最佳答案

您正在阅读的大多数建议(包括Loren的博客文章)都可能引用了旧版本的MATLAB,其bsxfunrepmat快很多。在R2013b中(请参阅链接中的“性能”部分),重新实现了repmat,以将其应用于数字,字符和逻辑参数时可大大提高性能。在最新版本中,它的速度可以与bsxfun相同。

对于它的值(value),在装有R2014a的机器上我得到了

m = 1e5;
n = 100;
A = rand(m,n);

frepmat = @() A - repmat(mean(A),size(A,1),1);
timeit(frepmat)

fbsxfun = @() bsxfun(@minus,A,mean(A));
timeit(fbsxfun)

ans =
      0.03756
ans =
     0.034831

因此bsxfun看起来仍然快一点点,但速度并不快-在您的计算机上,情况似乎恰恰相反。当然,如果更改A的大小或要应用的操作,则这些结果很可能会再次变化。

仍然有其他原因可能会优先选择一种解决方案,例如优雅(如果可能,我更喜欢bsxfun)。

编辑:评论者出于特定原因要求偏爱bsxfun,这意味着通过避免repmat不会使用的临时副本,它可能比repmat占用更少的内存。

我认为情况并非如此。例如,打开任务管理器(或Linux / Mac上的等效项),观察内存级别,然后键入:
>> m = 1e5; n = 8e3; A = rand(m,n);
>> B = A - repmat(mean(A),size(A,1),1);
>> clear B
>> C = bsxfun(@minus,A,mean(A));
>> clear C

(调整mn,直到在图表中看到跳转为止,但不要太大,以免耗尽内存)。

我从repmatbsxfun看到了完全相同的行为,那就是内存平稳地上升到新的水平(基本上是A的两倍),没有临时的额外峰值。

即使就地完成操作,情况也是如此。再次,注意内存并键入:
>> m = 1e5; n = 8e3; A = rand(m,n);
>> A = A - repmat(mean(A),size(A,1),1);
>> clear all
>> m = 1e5; n = 8e3; A = rand(m,n);
>> A = bsxfun(@minus,A,mean(A));

同样,我从repmatbsxfun看到了完全相同的行为,即内存上升到一个峰值(基本上是A大小的两倍),然后又下降到上一个级别。

因此,恐怕repmatbsxfun之间在速度或内存方面看不到太多技术差异。我对bsxfun的偏爱实际上只是个人偏爱,因为它感觉更优雅。

10-07 23:49