首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在MATLAB中,什么时候使用bsxfun是最好的?

在MATLAB中,什么时候使用bsxfun是最好的?
EN

Stack Overflow用户
提问于 2012-10-18 17:31:53
回答 5查看 28.1K关注 0票数 136

我注意到很多关于堆栈和溢出的MATLAB问题的好答案经常使用函数bsxfun。为什么?

动机:bsxfun的MATLAB文档中,提供了以下示例:

代码语言:javascript
运行
复制
A = magic(5);
A = bsxfun(@minus, A, mean(A))

当然,我们可以使用以下命令执行相同的操作:

代码语言:javascript
运行
复制
A = A - (ones(size(A, 1), 1) * mean(A));

事实上,一个简单的速度测试表明,第二种方法大约快20%。那么为什么要使用第一种方法呢?我猜在某些情况下,使用bsxfun会比使用“手动”方法快得多。我真的很有兴趣看到这种情况的例子,并解释为什么它更快。

同样,这个问题的最后一个元素,同样来自MATLAB的bsxfun文档:"C = bsxfun( fun,A,B)将由函数句柄fun指定的逐个元素的二进制操作应用于数组A和B,并启用单例扩展。“短语“启用单例扩展”是什么意思?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-10-18 21:19:42

我使用bsxfun有三个原因(documentationblog link)

  1. bsxfunrepmat更快(参见below)
  2. bsxfun需要更少的输入
  3. 使用bsxfun,就像使用accumarray一样,这让我对自己对MATLAB的理解感觉很好。

bsxfun将沿着输入数组的“单一维数”(即数组大小为1的维数)复制输入数组,以便它们与其他数组的相应维数的大小相匹配。这就是所谓的"singleton expansion“。顺便说一句,如果调用squeeze,单例维度将被删除。

对于非常小的问题,repmat方法可能会更快-但在这种数组大小下,这两种操作都非常快,可能不会对整体性能产生任何影响。bsxfun速度更快有两个重要原因:(1)计算发生在编译代码中,这意味着实际的数组复制永远不会发生,(2) bsxfun是多线程MATLAB函数之一。

我已经在我相当快的笔记本电脑上用MATLAB R2012b进行了repmatbsxfun之间的速度比较。

对我来说,bsxfun大约比repmat快三倍。当数组变得更大时,差异会变得更加明显:

repmat的运行时跳跃发生在1MB的数组大小附近,这可能与我的处理器缓存的大小有关- bsxfun的跳跃不会那么糟糕,因为它只需要分配输出数组。

下面是我用来计时的代码:

代码语言:javascript
运行
复制
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
票数 153
EN

Stack Overflow用户

发布于 2012-10-19 03:54:27

在我的例子中,我使用bsxfun,因为它避免了我考虑列或行问题。

为了编写您的示例:

代码语言:javascript
运行
复制
A = A - (ones(size(A, 1), 1) * mean(A));

我必须解决几个问题:

  1. size(A,1)size(A,2)

  1. ones(sizes(A,1),1)ones(1,sizes(A,1))

  1. ones(size(A, 1), 1) * mean(A)mean(A)*ones(size(A, 1), 1)

  1. mean(A)mean(A,2)

当我使用bsxfun时,我只需要解决最后一个问题:

a) mean(A)mean(A,2)

你可能认为它很懒,但是当我使用bsxfun时,我有更少的bugs和我更快的

此外,它更短,这提高了和readability.的键入速度

票数 41
EN

Stack Overflow用户

发布于 2012-10-18 17:45:30

非常有趣的问题!我最近在回答this question时偶然发现了这种情况。考虑以下代码,该代码通过向量a计算大小为3的滑动窗口的索引

代码语言:javascript
运行
复制
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几乎快了一倍!它是有用和快速的,因为它避免了显式地为矩阵idx0idx1分配内存,将它们保存到内存中,然后再次读取它们以添加它们。由于内存带宽是一项宝贵的资产,并且通常是当今体系结构上的瓶颈,因此您希望明智地使用它,并减少代码的内存需求以提高性能。

bsxfun允许您这样做:通过将任意运算符应用于两个向量的所有元素对来创建矩阵,而不是显式地对通过复制向量获得的两个矩阵进行操作。这是单例扩展。您也可以将其视为来自BLAS外部产品

代码语言:javascript
运行
复制
v1=[0:2]';
v2 = 1:numel(a)-2;
tic;
vout = v1*v2;
toc
Elapsed time is 0.309763 seconds.

将两个向量相乘得到一个矩阵。只是外积只执行乘法,bsxfun可以应用任意运算符。顺便说一句,看到bsxfun和BLAS外部产品一样快,这是非常有趣的。而BLAS通常被认为可以为提供性能...

多亏了丹的评论,这里有一个很棒的article by Loren讨论了这一点。

票数 17
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12951453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档