Как векторизовать это умножение матриц в Matlab - PullRequest
2 голосов
/ 07 апреля 2011

У меня есть 2 матрицы A (nxm) и B (nxd), и я хочу умножить поэлементно каждый столбец A на строку B. В столбце m A и n 1xd векторов в B, так что результатом являются m nxd матриц. Затем я хочу суммировать (result_i, 1), чтобы получить m 1xd векторов, которые я хочу применить vertcat, чтобы получить mxd матрицу. Я делаю эту операцию, используя цикл for, и он медленный, потому что n и d большие. Как я могу векторизовать это в Matlab, чтобы сделать это быстрее? Спасибо.

EDIT:
Вы в порядке: я был смущен своим собственным вопросом. Что я имел в виду под «умножением поэлементно каждого столбца A со строкой B», так это умножением n элементов столбца в A на соответствующие n строк в B. Что я хочу сделать с одним столбец A выглядит следующим образом (и я повторяю это для m столбцов A, а затем вертицируем вектор C вместе, чтобы получить матрицу mxd):

column_of_A =

     3
     3
     1


B =

     3     1     3     3
     2     2     1     2
     1     3     3     3


C = sum(diag(column_of_A)*B, 1)

     16    12    15    18

Ответы [ 3 ]

6 голосов
/ 07 апреля 2011

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

%# multiply nxm A with nx1xd B to create a nxmxd array
tmp = bsxfun(@times,A,permute(B,[1 3 2]));

%# sum and turn into mxd
out = squeeze(sum(tmp,1));

Возможно, вы захотите сделать все в одной строке, что поможет JIT-компилятору Matlab сэкономить на памяти.

EDIT

Вот способ заменить первую строку, если у вас нет bsxfun

[n,m] = size(A);
[n,d] = size(B);
tmp = repmat(A,[1 1 d]) .* repmat(permute(B,[1 3 2]),[1,m,1]);
1 голос
/ 07 апреля 2011

Это некрасиво, но, насколько я вижу, это работает. Я не уверен, что это будет быстрее, чем ваш цикл, хотя, кроме того, он имеет большие накладные расходы памяти. Во всяком случае, здесь идет:

A_3D = repmat(reshape(A, size(A, 1), 1, size(A, 2)), 1, size(B, 2));
B_3D = repmat(B, [ 1 1 size(A, 2)]);
result_3D = sum(A_3D .* B_3D, 1);
result = reshape(result_3D, size(A, 2), size(B, 2))

Что он делает: превращает A в трехмерную матрицу размером n x 1 x m, поэтому по одному столбцу в каждом индексе 3-го измерения. Затем мы повторяем матрицу, чтобы получить матрицу n x d x m. Мы повторяем B также в 3-м измерении. Затем мы делаем кусочное умножение всех элементов и суммируем их. Результирующая матрица представляет собой матрицу 1 x d x m. Мы преобразуем это в матрицу m x d.

Я почти уверен, что несколько раз менял размеры в своем объяснении, но я надеюсь, что вы получите общий смысл.

Умножение с диагональной матрицей кажется, по крайней мере, в два раза быстрее, но я не смог найти способ использовать diag, так как для него нужна векторная или 2D матрица в качестве входных данных. Я мог бы попытаться позже позже вечером, я чувствую, что должен быть более быстрый путь:).

[Edit] Разделите команду по частям, чтобы хотя бы сделать ее немного читабельной.

0 голосов
/ 24 апреля 2014

Вот как я бы это сделал:

сумма (repmat (А, 1,4). * В)

Если вы не знаете количество столбцов в B:

сумма (repmat (А, 1, размер (В, 2)). * В)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...