Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在MATLAB中,何时使用bsxfun是最佳选择?_Arrays_Matlab_Bsxfun - Fatal编程技术网

Arrays 在MATLAB中,何时使用bsxfun是最佳选择?

Arrays 在MATLAB中,何时使用bsxfun是最佳选择?,arrays,matlab,bsxfun,Arrays,Matlab,Bsxfun,我注意到,很多关于堆栈溢出的MATLAB问题的好答案经常使用函数bsxfun。为什么? 动机:在bsxfun的MATLAB文档中,提供了以下示例: A = magic(5); A = bsxfun(@minus, A, mean(A)) 当然,我们可以使用以下方法执行相同的操作: A = A - (ones(size(A, 1), 1) * mean(A)); 事实上,一个简单的速度测试表明第二种方法大约快20%。那么为什么要使用第一种方法呢?我猜在某些情况下,使用bsxfun将比“手动”方

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

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

A = magic(5);
A = bsxfun(@minus, A, mean(A))
当然,我们可以使用以下方法执行相同的操作:

A = A - (ones(size(A, 1), 1) * mean(A));
事实上,一个简单的速度测试表明第二种方法大约快20%。那么为什么要使用第一种方法呢?我猜在某些情况下,使用
bsxfun
将比“手动”方法快得多。我真的很想看看这种情况的例子,并解释为什么它更快


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

非常有趣的问题!我最近在回答这个问题时,恰好遇到了这种情况。考虑下面的代码,通过向量<代码> < <代码> > < /P>计算大小为3的滑动窗口的索引。
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
允许您这样做:在对两个向量的所有元素对应用任意运算符的基础上创建矩阵,而不是对通过复制向量获得的两个矩阵进行显式运算。这就是单例扩展。您也可以将其视为外部产品,来自:

将两个向量相乘得到一个矩阵。只是外积只执行乘法,
bsxfun
可以应用任意运算符。作为旁注,非常有趣的是看到
bsxfun
与BLAS外部产品一样快。BLAS通常被认为提供了性能


多亏了Dan的评论,这里有一个很好的讨论。我使用bsxfun的原因有三个(,)

  • bsxfun
    repmat
    快(见下文)
  • bsxfun
    需要更少的键入
  • 使用
    bsxfun
    ,就像使用
    accumarray
    ,使我对MATLAB的理解感觉良好
  • bsxfun
    将沿着其“单一维度”(即数组大小为1的维度)复制输入数组,以便它们与另一个数组的相应维度的大小匹配。这就是所谓的“我”。另一方面,如果调用
    挤压
    ,将删除单例维度

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

    我在速度非常快的笔记本电脑上用MATLAB R2012b在
    repmat
    bsxfun
    之间进行了速度比较

    对我来说,
    bsxfun
    大约比
    repmat
    快三倍。如果阵列变大,差异会变得更明显:

    repmat
    的运行时跳转发生在1 MB的数组大小附近,这可能与我的处理器缓存的大小有关-
    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
    

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

    为了编写您的示例:

    A = A - (ones(size(A, 1), 1) * mean(A));
    
    我必须解决几个问题:

  • 尺寸(A,1)
    尺寸(A,2)

  • one(尺寸(A,1),1)
    one(1,尺寸(A,1))

  • one(尺寸(A,1),1)*平均值(A)
    平均值(A)*one(尺寸(A,1),1)

  • 平均值(A)
    平均值(A,2)

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

    a)
    平均值(a)
    平均值(a,2)

    您可能会认为它很懒或是什么,但是当我使用
    bsxfun
    时,我的bug更少了,编程速度也更快了


    此外,它较短,从而提高了键入速度可读性

    事情并不总是与三种常用方法一致:
    repmat
    、逐项扩展索引和
    bsxfun
    。当进一步增加向量大小时,它会变得更有趣。见图表:


    bsxfun
    实际上在某一点上会比其他两个稍微慢一点,但让我吃惊的是,如果向量大小增加更多(>13E6个输出元素),bsxfun会突然变快3倍左右。他们的速度似乎一步一步地加快,而且顺序并不总是一致的。我的猜测是,它也可能取决于处理器/内存大小,但通常我认为只要有可能,我会坚持使用
    bsxfun

    从R2016b开始,MATLAB支持多种运算符,因此在大多数情况下不再需要使用
    bsxfunA = A - (ones(size(A, 1), 1) * mean(A));