我的问题:我注意到,很多好的答案Matlab的问题上如此频繁使用的功能的bsxfun
。 为什么?
动机:在Matlab的文档bsxfun
,提供了下面的例子:
A = magic(5);
A = bsxfun(@minus, A, mean(A))
当然,我们可以用做同样的操作:
A = A - (ones(size(A, 1), 1) * mean(A));
并且实际上是一个简单的速度测试表明了第二种方法是更快的约20%。 那么为什么要使用第一种方法? 我猜有一些情况,其中使用bsxfun
会比“手工”的方式快得多。 我会在看到这种情况的例子和解释为什么它是更快真的感兴趣。
此外,从Matlab的文档最后一个元件到这个问题,再次bsxfun
:“C = bsxfun(乐趣,A,B)应用由功能句柄乐趣指定阵列A和B的元件由元件二进制运算,用单扩能。“ 这个短语是什么“启用单扩张”是什么意思?
Answer 1:
原因有三我用bsxfun
( 文档 , 博客链接 )
-
bsxfun
快于repmat
(见下文) -
bsxfun
需要较少的打字 - 使用
bsxfun
,喜欢用accumarray
,让我感觉良好,我的Matlab的理解。
bsxfun
将复制输入阵列沿着它们的“单尺寸”,即尺寸沿该阵列的大小是1,以便它们匹配另一个阵列的对应尺寸的尺寸。 这就是所谓的“单expasion”。 顺便说一句,单件尺寸,如果你调用将被丢弃的那些squeeze
。
这可能是非常小的问题, repmat
做法是快-但在那个数组的大小,无论操作是如此之快,可能不会使整体性能方面的任何差异。 有两个重要的原因bsxfun
被更快:(1)计算发生在编译的代码,这意味着阵列的实际的复制不会发生,和(2) bsxfun
是多线程Matlab的功能之一。
我已经运行之间的速度比较repmat
和bsxfun
在我的体面快速笔记本电脑R2012b。
对我来说, bsxfun
比快3倍左右repmat
。 如果阵列得到较大的差别变得更加明显
在运行时的跳跃repmat
发生的1Mb的数组大小,这可能是与我的处理器缓存的大小左右- bsxfun
没有得到坏跳的,因为它只需要分配输出数组。
下面你可以看到我用于定时的代码:
n = 300;
k=1; %# k=100 for the second graph
a = ones(10,1);
rr = zeros(n,1);
bb=zeros(n,1);
ntt=100;
tt=zeros(ntt,1);
for i=1:n;
r = rand(1,i*k);
for it=1:ntt;
tic,
x=bsxfun(@plus,a,r);
tt(it)=toc;
end;
bb(i)=median(tt);
for it=1:ntt;
tic,
y=repmat(a,1,i*k)+repmat(r,10,1);
tt(it)=toc;
end;
rr(i)=median(tt);
end
Answer 2:
就我而言,我使用bsxfun
,因为它避免了我思考的行或列的问题。
为了写你的例子:
A = A - (ones(size(A, 1), 1) * mean(A));
我必须解决几个问题:
1) size(A,1)
或size(A,2)
2) ones(sizes(A,1),1)
或ones(1,sizes(A,1))
3) ones(size(A, 1), 1) * mean(A)
或mean(A)*ones(size(A, 1), 1)
4) mean(A)
或mean(A,2)
当我使用bsxfun
,我只是要解决的最后一个:
一) mean(A)
或mean(A,2)
你可能会认为这是偷懒什么的,但是当我使用bsxfun
,我有较少的错误 ,我编程更快 。
此外,它是较短的,从而提高打字速度和可读性 。
Answer 3:
非常有趣的问题! 我最近正好在这样的情况下绊倒在回答这个问题。 考虑下面的代码,其通过矢量计算大小为3的滑动窗口的索引a
:
a = rand(1e7,1);
tic;
idx = bsxfun(@plus, [0:2]', 1:numel(a)-2);
toc
% equivalent code from im2col function in MATLAB
tic;
idx0 = repmat([0:2]', 1, numel(a)-2);
idx1 = repmat(1:numel(a)-2, 3, 1);
idx2 = idx0+idx1;
toc;
isequal(idx, idx2)
Elapsed time is 0.297987 seconds.
Elapsed time is 0.501047 seconds.
ans =
1
在这种情况下bsxfun
几乎快两倍! 因为它避免了内存矩阵明确的分配是非常有用的,快速idx0
和idx1
,将它们保存到内存中,然后再读取它们只是添加。 由于内存带宽是一笔宝贵的财富,并经常在今天架构的瓶颈,要明智地使用它,并降低你的代码的内存需求,以提高性能。
bsxfun
可以让你做到这一点:创建基于应用的任意运营商都对两个向量的元素,而不是在通过复制矢量获得两个矩阵明确操作的矩阵。 这是单身扩张 。 你也可以考虑一下从BLAS 外产品 :
v1=[0:2]';
v2 = 1:numel(a)-2;
tic;
vout = v1*v2;
toc
Elapsed time is 0.309763 seconds.
您乘两个向量得到一基质。 只是,外产品仅执行乘法和bsxfun
可以申请任意的运营商。 作为一个方面说明,这是非常有趣的是, bsxfun
是作为BLAS外产品一样快。 而BLAS通常被认为是为客户提供性能..
编辑感谢Dan的评论,这里是一个伟大的洛伦文章正是讨论。
Answer 4:
作为R2016b的,MATLAB支持隐扩展为各种运营商的,所以在大多数情况下,它不再需要使用bsxfun
:
此前,这个功能是通过提供bsxfun
功能。 现在建议您更换的大多数使用bsxfun
直接调用支持隐扩展的功能和运营商。 相比于使用bsxfun
, 隐含的扩张提供了更快的速度 , 更好的内存使用情况 ,以及改进的代码的可读性 。
有一个详细的讨论 隐式扩张及其对罗兰的博客性能。 要引用来自MathWorks的史蒂夫Eddins:
在R2016b, 隐扩建工程一样快或快于bsxfun
在大多数情况下。 对于隐式扩张的最佳性能增益与小矩阵和阵列尺寸。 对于大的矩阵大小,隐式膨胀趋于大致相同的速度bsxfun
。
Answer 5:
事情并不总是与3个常用的方法是一致的: repmat
,由312104那些索引和bsxfun
。 当你增加了矢量大小甚至进一步变得相当有趣。 参见图:
bsxfun
实际上变得比其他两种在某些时候稍微慢一些,但让我吃惊是,如果你约3倍再次增长较快的矢量大小更(> 13E6输出元素),bsxfun突然变。 他们的速度似乎在步跳和顺序并不总是一致的。 我的猜测是,它可能是处理器/内存的大小依赖太多,但总体上我想我会坚持使用bsxfun
只要有可能。
文章来源: In Matlab, when is it optimal to use bsxfun?