【问题标题】:special add in matlab [duplicate]matlab中的特殊添加[重复]
【发布时间】:2012-07-27 19:19:28
【问题描述】:

可能重复:
How to Add a row vector to a column vector like matrix multiplication

我有一个nx1 向量和一个1xn 向量。我想以一种特殊的方式添加它们,比如以一种有效的方式(矢量化)进行矩阵乘法:

例子:

A=[1 2 3]'

B=[4 5 6]

A \odd_add B = 
[1+4 1+5 1+6
 2+4 2+5 2+6
 3+4 3+5 3+6
]

我在 MATLAB 中使用过bsxfun,但我认为它很慢。请帮帮我...

【问题讨论】:

标签: matlab vectorization addition


【解决方案1】:

正如@b3 所述。这将是使用repmat 的合适位置。但总的来说,尤其是在处理非常大的矩阵时,bsxfun 通常是更好的替代品。在这种情况下:

>> bsxfun(@plus, [1,2,3]', [4,5,6])

返回相同的结果,使用大矩阵限制中大约三分之一的内存。

bsxfun 基本上将第一个参数中的函数应用于第二个和第三个参数中的每个项目组合,根据输入向量的形状将结果放入矩阵中。

【讨论】:

    【解决方案2】:

    我比较了这里提到的不同方法。我正在使用TIMEIT 函数来获得可靠的估计(负责预热代码、多次运行的平均时间......):

    function testBSXFUN(N)
        %# data
        if nargin < 1
            N = 500;        %# N = 10, 100, 1000, 10000
        end
        A = (1:N)';
        B = (1:N);
    
        %# functions
        f1 = @() funcRepmat(A,B);
        f2 = @() funcTonyTrick(A,B);
        f3 = @() funcBsxfun(A,B);
    
        %# timeit
        t(1) = timeit( f1 );
        t(2) = timeit( f2 );
        t(3) = timeit( f3 );
    
        %# time results
        fprintf('N = %d\n', N);
        fprintf('REPMAT: %f, TONY_TRICK: %f, BSXFUN: %f\n', t);
    
        %# validation
        v{1} = f1();
        v{2} = f2();
        v{3} = f3();
        assert( isequal(v{:}) )
    end
    

    在哪里

    function C = funcRepmat(A,B)
        N = numel(A);
        C = repmat(A,1,N) + repmat(B,N,1);
    end
    
    function C = funcTonyTrick(A,B)
        N = numel(A);
        C = A(:,ones(N,1)) + B(ones(N,1),:);
    end
    
    function C = funcBsxfun(A,B)
        C = bsxfun(@plus, A, B);
    end
    

    时间安排:

    >> for N=[10 100 1000 5000], testBSXFUN(N); end
    N = 10
    REPMAT: 0.000065, TONY_TRICK: 0.000013, BSXFUN: 0.000031
    N = 100
    REPMAT: 0.000120, TONY_TRICK: 0.000065, BSXFUN: 0.000085
    N = 1000
    REPMAT: 0.032988, TONY_TRICK: 0.032947, BSXFUN: 0.010185
    N = 5000
    REPMAT: 0.810218, TONY_TRICK: 0.824297, BSXFUN: 0.258774
    

    BSXFUN 无疑是赢家。

    【讨论】:

    • 感谢您的回答。请您也测试我的解决方案。它基于常规矩阵乘法。首先使用 exp(),然后 C=A*B,最后使用 result=log(C)。由于我想检查最终结果中的负值,因此可以忽略最后一个命令(日志)。
    • @remo:虽然您的解决方案在数学上是正确的C = log(exp(A)*exp(B)),但它并不总是在数值上可用。例如,如果您在 MATLAB 中键入 exp(750),您将简单地得到 Inf(数字太大而无法用双精度浮点数表示)...
    • @remo: 对于它的价值,我只是用N=350 对其进行了测试,它比上述所有方法都慢(N 的较大值在结果中有Inf)。我猜explog 不是廉价操作
    【解决方案3】:

    在 matlab 矢量化中,与 repmat 或任何其他内置的 Matlab 函数相比,Tony's Trick 在速度方面无可替代。我确信以下代码对于您的目的来说必须是最快的。

    >> A = [1 2 3]';
    >> B = [4 5 6];
    >> AB_sum = A(:,ones(3,1)) + B(ones(3,1),:);
    

    对于较大的AB,速度差异将更加明显(至少一个数量级)。看到这个test我前段时间进行了确定Tony's Trick在时间消耗方面优于repmat

    【讨论】:

    • 虽然Tony's trick 在大多数情况下都比 REPMAT 好(正如您在链接答案中所展示的那样),但在这种情况下,BSXFUN 在时间和空间消耗方面都具有优势(因为它实际上不需要复制内存中的两个向量)。就像您之前所做的一样,我发布了一个性能比较来支持我的主张:)
    • @Amro 感谢经验结果.. .
    【解决方案4】:

    REPMAT是你的朋友:

    >> A = [1 2 3]'; >> B = [4 5 6]; >> AplusB = repmat(A, 1, 3) + repmat(B, 3, 1) 加 B = 5 6 7 6 7 8 7 8 9

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-10
      • 1970-01-01
      • 2015-08-10
      相关资源
      最近更新 更多