Получить много трехмерных матриц из двух двумерных матриц (умножение по столбцам)
Есть ли более быстрый способ выполнить следующую операцию без цикла?
n = 2;
m = 1000;
A = rand(n,m);
B = rand(n,m);
C = zeros(n*n,m);
for i = 1 : m
tmp = A(:,i) * B(:,i)';
C(:,i) = tmp(:);
end
В основном мне нужно получить m
nxn
матрицы с матричным умножением матриц между столбцами A
а также B
, Тогда мне нужна векторизация таких матриц.
2 ответа
Вы в основном выполняете поэлементное умножение для всех столбцов в A
против всех столбцов, но транспонирован в B
, Вы можете иметь один векторизованный подход с bsxfun(@times,..)
в основном убивает / заменяет эти неприятные петли bsxfun
мощные возможности внутреннего расширения. Реализация также будет включать изменение формы, чтобы оно было в том же формате, что и C
и будет выглядеть примерно так -
out = reshape(bsxfun(@times,permute(A,[1 3 2]),permute(B,[3 1 2])),n^2,[])
Испытания во время выполнения
В этом разделе сравниваются все перечисленные подходы для решения проблемы.
Код бенчмаркинга -
%// Inputs
n = 2;
m = 1000;
A = rand(n,m);
B = rand(n,m);
num_iter = 5000;
disp('-------------------- For loop NO fuN') %// From OP question
tic
for iter = 1:num_iter
C = zeros(n*n,m);
for i = 1 : m
tmp = A(:,i) * B(:,i)';
C(:,i) = tmp(:);
end
end
toc
disp('-------------------- run run KRON') %'// @lhcgeneva's solution
tic
for iter = 1:num_iter
A1 = repmat(A, n, 1);
B1 = kron(B,ones(n,1));
D = reshape(A1(:).*B1(:), n*n, m);
end
toc
disp('-------------------- fun fun BSXFUN') %// Proposed in this post
tic
for iter = 1:num_iter
out = reshape(bsxfun(@times,permute(A,[1 3 2]),permute(B,[3 1 2])),n^2,[]);
end
toc
Выход -
-------------------- For loop NO fuN
Elapsed time is 28.101873 seconds.
-------------------- run run KRON
Elapsed time is 1.156337 seconds.
-------------------- fun fun BSXFUN
Elapsed time is 0.692433 seconds.
Вы можете полностью векторизовать это используя repmat, kron и reshape или, используя решение Divakar с bsxfun
, permute
а также repmat
что дает вам еще одно значительное улучшение с точки зрения скорости.
tic
for j = 1:1000
A1 = repmat(A, n, 1);
B1 = kron(B,ones(n,1));
D = reshape(A1(:).*B1(:), n*n, m);
end
toc
Прошедшее время составляет 0,117396 секунд.
tic
for j = 1:1000
C = zeros(n*n,m);
for i = 1 : m
tmp = A(:,i) * B(:,i)';
C(:,i) = tmp(:);
end
end
toc
Прошедшее время составляет 5,751179 секунд.
Таким образом, ускорение составляет около 50 раз. Однако, как обсуждалось в комментариях ниже, ускорение, как обычно, зависит от размера матриц и количества выполнений задачи.