如何在不使用MATLAB循环的情况下从行向量和列向量创建矩阵?

时间:2017-03-24 13:42:29

标签: matlab loops matrix vector vectorization

我有两个向量,比如大小为nx1的A和大小为1xm的B。我想从非线性公式创建结果矩阵C(nxm),以便

C(i,j) = A(i)/(A(i)+B(j)).

我知道我可以通过循环执行此操作,例如:

for i=1:n,
    C(i,1:m)=A(i)./(A(i)+B(1:m));
end

但是可以通过某种方式在不使用循环的情况下完成此操作吗?

编辑:谢谢你的回答!作为一个小小的补充,在我看到它们之前,一位朋友提出了以下解决方案:

C = A*ones(1,m)./(ones(n,1)*B+A*ones(1,m))

2 个答案:

答案 0 :(得分:6)

如果您使用的是MATLAB R2016a或更早版本,那么您将希望使用bsxfun来完成此任务

result = bsxfun(@rdivide, A, bsxfun(@plus, A, B));

如果您使用的是R2016b或更新版本,则会有隐式扩展,允许您删除bsxfun并直接应用元素运算符

result = A ./ (A + B);

<强>基准

以下是使用timeit比较使用bsxfunrepmat,隐式广播和for循环的执行速度的真实基准。从结果中可以看出,bsxfun和隐式广播方法产生的执行时间最快。

function comparision()

    sz = round(linspace(10, 5000, 30));

    times1 = nan(size(sz));
    times2 = nan(size(sz));
    times3 = nan(size(sz));
    times4 = nan(size(sz));

    for k = 1:numel(sz)
        A = rand(sz(k), 1);
        B = rand(1, sz(k));
        times1(k) = timeit(@()option1(A,B));
        A = rand(sz(k), 1);
        B = rand(1, sz(k));
        times2(k) = timeit(@()option2(A,B));
        A = rand(sz(k), 1);
        B = rand(1, sz(k));
        times3(k) = timeit(@()option3(A,B));
        A = rand(sz(k), 1);
        B = rand(1, sz(k));
        times4(k) = timeit(@()option4(A,B));
    end

    figure
    p(1) = plot(sz, times1 * 1000, 'DisplayName', 'bsxfun');
    hold on
    p(2) = plot(sz, times2 * 1000, 'DisplayName', 'repmat');
    p(3) = plot(sz, times3 * 1000, 'DisplayName', 'implicit');
    p(4) = plot(sz, times4 * 1000, 'DisplayName', 'for loop');
    ylabel('Execution time (ms)')
    xlabel('Elements in A')
    legend(p)
end

function C = option1(A,B)
    C = bsxfun(@rdivide, A, bsxfun(@plus, A, B));
end

function C = option2(A,B)
    m = numel(B);
    n = numel(A);
    C = repmat(A,1,m) ./ (repmat(A,1,m) + repmat(B,n,1));
end

function C = option3(A, B)
    C = A ./ (A + B);
end

function C = option4(A, B)
    m = numel(B);
    n = numel(A);
    C = zeros(n, m);
    for i=1:n,
        C(i,1:m)=A(i)./(A(i)+B(1:m));
    end
end

enter image description here

有关隐式扩展和bsxfun的比较详情,请参阅此answer

答案 1 :(得分:1)

如Suever所提到的,如果你有2016b或更新的话,隐式扩展就是你要走的路。没有这个的另一种方法是在使用repmat使A和B与C相同之后进行逐元素操作...

A1 = repmat(A,1,m);
B1 = repmat(B,n,1);
C = A1 ./ (A1 + B1);

或者在一行......

C = repmat(A,1,m) ./ (repmat(A,1,m) + repmat(B,n,1));

作为基准测试,我运行了你的循环方法,上面的repmat方法,以及bsxfun的Suever m = 1000, n = 100方法,每个方法平均超过1,000次运行:

Using for loop 0.00290520 sec
Using repmat   0.00014693 sec
Using bsxfun   0.00016402 sec

因此,对于大型矩阵,repmatbsxfunrepmat边缘相当。但是对于小矩阵,只需循环就可以比两者都快,特别是使用小n,这就是你的循环变量!

值得测试特定用例的给定方法,因为时序结果看起来相当可变,具体取决于输入。