我正在努力寻找在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,其中bsxfun
比repmat
快得多。在R2013b中(请参阅链接中的"性能"部分),repmat
被重新实现,以在应用于数字、字符和逻辑参数时提供巨大的性能改进。在最近的版本中,它的速度可能与bsxfun
大致相同。
值得一提的是,在我的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
(调整m
和n
,直到跳跃在图形中可见,但不要太大以至于内存不足)。
我从repmat
和bsxfun
中看到了完全相同的行为,即内存平稳地上升到新的水平(基本上是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));
同样,我从repmat
和bsxfun
中看到了完全相同的行为,即内存上升到峰值(基本上是A
的两倍),然后回落到以前的水平。
所以我恐怕看不出repmat
和bsxfun
在速度或内存方面有多大的技术差异。我对bsxfun
的偏好实际上只是个人偏好,因为它感觉更优雅一些。