2012-07-27 50 views
0

可能重复:
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,但我认为它是缓慢的。请帮我...

+2

这是完全一样的前一个问题http://stackoverflow.com/questions/11690743/how-to-add-a-row-vector-to-a-column-vector-like-matrix-multiplication – mathematician1975 2012-07-27 19:29:01

+0

对不起,但速度是问题所在。我在那里回答了你的评论。 – remo 2012-07-28 02:16:03

回答

0

REPMAT是你的朋友:

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

AplusB = 

    5  6  7 
    6  7  8 
    7  8  9 
2

正如@ B3提及。这将是一个适当的地方使用repmat。然而,一般来说,尤其是如果你正在处理非常大的矩阵,bsxfun通常是一个更好的替代品。在这种情况下:

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

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

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

1

在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在时间消耗方面的优势。

+0

虽然'Tony's trick'在大多数情况下都优于REPMAT(正如您在关联答案中显示的那样),在这种情况下,BSXFUN在时间和空间消耗方面都具有优势(因为它实际上并不需要复制记忆中的两个向量)。就像你以前一样,我发布了一个性能比较来备份我的说法:) – Amro 2012-07-29 19:03:16

+0

@Amro感谢您的实证结果..。 – Abhinav 2012-08-01 06:51:07

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是一个明显的赢家。

+0

谢谢你的回答。你还可以测试我的解决方案吗?它基于规则矩阵乘法。首先使用exp(),然后C = A * B,最后得到结果= log(C)。由于我想检查最终结果中的负值,因此可以忽略最后一个命令(日志)。 – remo 2012-07-30 00:37:15

+0

@remo:虽然你的解决方案在数学上正确的'C = log(exp(A)* exp(B))',它并不总是数字可用的。例如,如果你在MATLAB中输入'exp(750)',你将会得到'Inf'(数字太大而不能用双精度浮点数表示)... – Amro 2012-07-30 01:17:15

+0

@remo:为什么它的价值,我只是用'N = 350'测试它,它比上述所有方法都慢(对于'N'来说,较大的值在结果中有'Inf')。我猜'exp'和'log'不是便宜的操作 – Amro 2012-07-30 01:24:33