7

As always trying to learn more from you, I was hoping I could receive some help with the following code.

I need to accomplish the following:

1) I have a vector:

x = [1 2 3 4 5 6 7 8 9 10 11 12]

2) and a matrix:

A =[11    14    1
    5     8    18
    10    8    19
    13    20   16]

I need to be able to multiply each value from x with every value of A, this means:

new_matrix = [1* A
              2* A
              3* A
               ...
              12* A]

This will give me this new_matrix of size (12*m x n) assuming A (mxn). And in this case (12*4x3)

How can I do this using bsxfun from matlab? and, would this method be faster than a for-loop?

Regarding my for-loop, I need some help here as well... I am not able to storage each "new_matrix" as the loop runs :(

for i=x
new_matrix = A.*x(i)
end

Thanks in advance!!

EDIT: After the solutions where given

First solution

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

Output:

Elapsed time is 7.597939 seconds.

Second solution

clear all
clc
x=1:0.1:50;
A = rand(1000,1000);
tic
Ps = kron(x.',A);
toc

Output:

Elapsed time is 48.445417 seconds.
4

5 回答 5

17

发送到第三维,这样当与 相乘x时单例展开生效,将乘积结果扩展到第三维。然后,执行乘法 -bsxfunAbsxfun

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

现在,val是一个3D矩阵,期望的输出是一个2D矩阵,通过第三维沿列连接。这是在下面实现的 -

out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[])

希望这是有道理的!bsxfun到处传播!呜!!:)

于 2014-05-22T13:28:02.673 回答
10

kron功能正是这样做的:

kron(x.',A)
于 2014-05-22T13:52:20.910 回答
3

这是我到目前为止提到的方法的基准,以及我自己的一些补充:

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)

(这些时间在不同的运行之间可能会略有不同,但这应该让我们了解这些方法是如何比较的)

请注意,其中一些方法会导致较大输入的内存不足错误(例如,我基于的解决方案repmat很容易耗尽内存)。对于较大的尺寸,其他的会明显变慢,但不会由于内存耗尽而出错(kron例如解决方案)。

我认为这种bsxfun方法func2_bsxfun_3rd_dim或直接的 for 循环func4_forloop_matrix(感谢 MATLAB JIT)是这种情况下的最佳解决方案。

当然,您可以更改上述基准参数(和的大小xA并得出自己的结论:)

于 2014-06-24T17:46:04.860 回答
2

只是为了添加一个替代方案,您也许可以使用 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

于 2014-06-14T16:23:54.213 回答
0

如果您的向量 x 的长度 = 12 并且您的矩阵大小为 3x4,我认为使用其中一个或另一个不会在时间上发生太大变化。如果您正在使用更大尺寸的矩阵和向量,现在这可能会成为一个问题。

所以首先,我们想将一个向量与一个矩阵相乘。在 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

这将为您提供 3D 矩阵,每个 3 维都是乘法的结果。如果这不是您正在寻找的,我将添加另一个解决方案,它可能会使用更大的矩阵和向量来提高时间效率。

于 2014-05-22T13:30:59.840 回答