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] 

我需要能够将xevery值与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发送到第三维,以便当使用bsxfunA相乘时单例扩展生效,将产品结果扩展到第三维。 然后,执行bsxfun乘法 –

 val = bsxfun(@times,A,permute(x,[3 1 2])) 

现在, val是一个3Dmatrix,期望的输出是一个2Dmatrix,沿着三维的列连接起来。 这在下面实现 –

 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。

当然,你可以改变上面的基准参数( xA大小),并画出你自己的结论:)

只是添加一个替代品,你也许可以使用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和向量的时间效率。