bsxfun在matrix乘法中的实现
一如既往地试图从你那里学到更多东西,我希望能够通过下面的代码获得一些帮助。
我需要完成以下内容:
1)我有一个vector:
x = [1 2 3 4 5 6 7 8 9 10 11 12]
2)和一个matrix:
A =[11 14 1 5 8 18 10 8 19 13 20 16]
我需要能够将x
的every
值与A
each
值相乘,这意味着:
new_matrix = [1* A 2* A 3* A ... 12* A]
这会给我这个size (12*mxn)
new_matrix
,假设A (mxn)
。 而在这种情况下(12*4x3)
我怎样才能做到这一点,使用matlab的bsxfun
? 而且,这个方法会比for-loop
更快吗?
关于我的for-loop
,我需要一些帮助,以及…我不能够存储每个"new_matrix"
循环运行:(
for i=x new_matrix = A.*x(i) end
提前致谢!!
编辑:在给定的解决scheme之后
首先解决scheme
clear all clc x=1:0.1:50; A = rand(1000,1000); tic val = bsxfun(@times,A,permute(x,[3 1 2])); out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]); toc
输出:
Elapsed time is 7.597939 seconds.
第二种scheme
clear all clc x=1:0.1:50; A = rand(1000,1000); tic Ps = kron(x.',A); toc
输出:
Elapsed time is 48.445417 seconds.
将x
发送到第三维,以便当使用bsxfun
与A
相乘时单例扩展生效,将产品结果扩展到第三维。 然后,执行bsxfun
乘法 –
val = bsxfun(@times,A,permute(x,[3 1 2]))
现在, val
是一个3D
matrix,期望的输出是一个2D
matrix,沿着三维的列连接起来。 这在下面实现 –
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[])
希望这是有道理的! 传播bsxfun
话! 呜! 🙂
kron
函数的确如此:
kron(x.',A)
这是我迄今提到的方法的基准,以及我自己的一些补充:
function [t,v] = testMatMult() % data %{ x = [1 2 3 4 5 6 7 8 9 10 11 12]; A = [11 14 1; 5 8 18; 10 8 19; 13 20 16]; %} x = 1:50; A = randi(100, [1000,1000]); % functions to test fcns = { @() func1_repmat(A,x) @() func2_bsxfun_3rd_dim(A,x) @() func2_forloop_3rd_dim(A,x) @() func3_kron(A,x) @() func4_forloop_matrix(A,x) @() func5_forloop_cell(A,x) @() func6_arrayfun(A,x) }; % timeit t = cellfun(@timeit, fcns, 'UniformOutput',true); % check results v = cellfun(@feval, fcns, 'UniformOutput',false); isequal(v{:}) %for i=2:numel(v), assert(norm(v{1}-v{2}) < 1e-9), end end % Amro function B = func1_repmat(A,x) B = repmat(x, size(A,1), 1); B = bsxfun(@times, B(:), repmat(A,numel(x),1)); end % Divakar function B = func2_bsxfun_3rd_dim(A,x) B = bsxfun(@times, A, permute(x, [3 1 2])); B = reshape(permute(B, [1 3 2]), [], size(A,2)); end % Vissenbot function B = func2_forloop_3rd_dim(A,x) B = zeros([size(A) numel(x)], 'like',A); for i=1:numel(x) B(:,:,i) = x(i) .* A; end B = reshape(permute(B, [1 3 2]), [], size(A,2)); end % Luis Mendo function B = func3_kron(A,x) B = kron(x(:), A); end % SergioHaram & TheMinion function B = func4_forloop_matrix(A,x) [m,n] = size(A); p = numel(x); B = zeros(m*p,n, 'like',A); for i=1:numel(x) B((i-1)*m+1:i*m,:) = x(i) .* A; end end % Amro function B = func5_forloop_cell(A,x) B = cell(numel(x),1); for i=1:numel(x) B{i} = x(i) .* A; end B = cell2mat(B); %B = vertcat(B{:}); end % Amro function B = func6_arrayfun(A,x) B = cell2mat(arrayfun(@(xx) xx.*A, x(:), 'UniformOutput',false)); end
我的机器上的结果:
>> t t = 0.1650 %# repmat (Amro) 0.2915 %# bsxfun in the 3rd dimension (Divakar) 0.4200 %# for-loop in the 3rd dim (Vissenbot) 0.1284 %# kron (Luis Mendo) 0.2997 %# for-loop with indexing (SergioHaram & TheMinion) 0.5160 %# for-loop with cell array (Amro) 0.4854 %# arrayfun (Amro)
(这些时间可以在不同运行间稍微改变,但这应该让我们知道方法如何比较)
请注意,这些方法中的一些会导致更大的input内存不足错误(例如,基于repmat
我的解决scheme可以很容易地运行内存不足)。 其他人对于较大的尺寸会显着变慢,但不会由于内存耗尽而导致错误(例如kron
解决scheme)。
我认为在这种情况下, bsxfun
方法func2_bsxfun_3rd_dim
或简单的for-loop func4_forloop_matrix
(感谢MATLAB JIT)是最好的解决scheme。
当然,你可以改变上面的基准参数( x
和A
大小),并画出你自己的结论:)
只是添加一个替代品,你也许可以使用cellfun来实现你想要的。 这是一个例子(稍微修改你的):
x = randi(2, 5, 3)-1; a = randi(3,3); %// bsxfun 3D (As implemented in the accepted solution) val = bsxfun(@and, a, permute(x', [3 1 2])); %//' out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]); %// cellfun (My solution) val2 = cellfun(@(z) bsxfun(@and, a, z), num2cell(x, 2), 'UniformOutput', false); out2 = cell2mat(val2); % or use cat(3, val2{:}) to get a 3D matrix equivalent to val and then permute/reshape like for out %// compare disp(nnz(out ~= out2));
两者给出相同的确切结果。
有关使用cellfun的更多信息和技巧,请参阅: http ://matlabgeeks.com/tips-tutorials/computation-using-cellfun/
而且这也是: https : //stackoverflow.com/a/1746422/1121352
如果你的向量x的长度等于12而你的matrix的大小是3×4,那么我认为使用其中一个或者另一个的时间就不会变化很多。 如果你正在处理更大的matrix和向量,现在可能会成为一个问题。
所以首先,我们要用一个matrix乘以一个向量。 在for-loop方法中,会给出类似的结果:
s = size(A); new_matrix(s(1),s(2),numel(x)) = zeros; %This is for pre-allocating. If you have a big vector or matrix, this will help a lot time efficiently. for i = 1:numel(x) new_matrix(:,:,i)= A.*x(i) end
这会给你3Dmatrix,每个第三维是你乘法的结果。 如果这不是你正在寻找的,我会添加另一个解决scheme,这可能是更大的matrix和向量的时间效率。