2012-07-27 49 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