специальное добавление в Matlab

Возможный дубликат:
Как добавить вектор-строку в вектор-столбец, например умножение матриц

У меня есть вектор 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
]

Я использовал bsxfun в MATLAB, но я думаю, что это медленно. Пожалуйста помогите...


person remo    schedule 27.07.2012    source источник
comment
Это точно так же, как ваш предыдущий вопрос умножение" title="как добавить вектор-строку в вектор-столбец, например умножение матриц"> stackoverflow.com/questions/11690743/   -  person mathematician1975    schedule 27.07.2012
comment
Извините, но проблема была в скорости. Я ответил на ваш комментарий там.   -  person remo    schedule 28.07.2012


Ответы (4)


Как упоминал @b3. это было бы подходящим местом для использования repmat. Однако в целом, и особенно если вы имеете дело с очень большими матрицами, bsxfun обычно является лучшей заменой. В этом случае:

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

возвращает тот же результат, используя примерно треть памяти в пределе большой матрицы.

bsxfun в основном применяет функцию в первом аргументе к каждой комбинации элементов во втором и третьем аргументах, помещая результаты в матрицу в соответствии с формой входных векторов.

person Isaac    schedule 27.07.2012

Я представляю сравнение различных методов, упомянутых здесь. Я использую функцию 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 — явный победитель.

person Amro    schedule 29.07.2012
comment
Спасибо за ваш ответ. Не могли бы вы также протестировать мое решение. он основан на обычном умножении матриц. сначала используйте exp(), затем C=A*B и, наконец, результат=log(C). Поскольку я хочу проверить отрицательные значения в конечном результате, можно было бы игнорировать последнюю команду (журнал). - person remo; 30.07.2012
comment
@remo: хотя ваше решение математически правильно C = log(exp(A)*exp(B)), его не всегда можно использовать в числовых значениях. Например, если вы наберете exp(750) в MATLAB, вы просто получите Inf (слишком большое число для представления с плавающей запятой двойной точности)... - person Amro; 30.07.2012
comment
@remo: как бы то ни было, я только что протестировал его с помощью N=350, он был медленнее, чем все вышеперечисленные методы (большие значения для N имели в результате Inf). Я думаю, exp и log не дешевые операции - person Amro; 30.07.2012

В векторизации Matlab нет замены Tony's Trick с точки зрения скорости по сравнению с repmat или любой другой встроенной функцией Matlab в этом отношении. Я уверен, что следующий код должен быть самым быстрым для вашей цели.

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

Разница в скорости будет намного более очевидной (как минимум на порядок) для больших размеров A и B. См. этот тест, который я провел некоторое время назад, чтобы убедиться в превосходстве Tony's Trick над repmat с точки зрения затрат времени.

person Abhinav    schedule 27.07.2012
comment
Хотя Tony's trick в большинстве случаев лучше, чем REPMAT (как вы показали в своем связанном ответе), в этом случае BSXFUN имеет преимущество как с точки зрения времени, так и с точки зрения потребления пространства (поскольку на самом деле не требуется репликация двух векторов в памяти ). Как и вы ранее, я опубликовал сравнение производительности, чтобы подтвердить свои утверждения :) - person Amro; 29.07.2012
comment
@Amro Спасибо за эмпирические результаты.. . - person Abhinav; 01.08.2012

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
person b3.    schedule 27.07.2012