6

Matlabでループを回避しようと必死にforなっていますが、その方法がわかりません。状況は次のとおりです。

2つのm x n行列AB2つのベクトルがvありw、長さはdです。私は外部乗算をしたいAので、エントリがである行列vを取得し、同様にと。m x n x d(i,j,k)A_(i,j) * v_kBw

m x n x dその後、結果の行列を追加しmean、最後の次元に沿ってm x n行列を取得します。

後半は大丈夫だと思いますが、前半は完全に行き詰まってしまいます。bsxfun無駄に使ってみました。誰もがこれを行うための効率的な方法を知っていますか?どうもありがとう!

編集:この改訂は、以下の3つの優れた回答の後に行われます。gnoviceは、間違いなく私が尋ねた質問に対する最良の答えを持っています。しかし、私が尋ねるつもりだった質問は、平均を取る前に各エントリを二乗することを含みます。もともとこの部分について言及するのを忘れていました。この煩わしさを考えると、他の両方の答えはうまく機能しますが、コーディングの前に代数を実行するという巧妙なトリックは、今回は役に立ちません。皆さん、助けてくれてありがとう!

4

4 に答える 4

7

EDIT:

Even though the problem in the question has been updated, an algebraic approach can still be used to simplify matters. You still don't have to bother with 3-D matrices. Your result is just going to be this:

output = mean(v.^2).*A.^2 + 2.*mean(v.*w).*A.*B + mean(w.^2).*B.^2;

If your matrices and vectors are large, this solution will give you much better performance due to the reduced amount of memory required as compared to solutions using BSXFUN or REPMAT.


Explanation:

Assuming M is the m-by-n-by-d matrix that you get as a result before taking the mean along the third dimension, this is what a span along the third dimension will contain:

M(i,j,:) = A(i,j).*v + B(i,j).*w;

In other words, the vector v scaled by A(i,j) plus the vector w scaled by B(i,j). And this is what you get when you apply an element-wise squaring:

M(i,j,:).^2 = (A(i,j).*v + B(i,j).*w).^2;
            = (A(i,j).*v).^2 + ...
              2.*A(i,j).*B(i,j).*v.*w + ...
              (B(i,j).*w).^2;

Now, when you take the mean across the third dimension, the result for each element output(i,j) will be the following:

output(i,j) = mean(M(i,j,:).^2);
            = mean((A(i,j).*v).^2 + ...
                   2.*A(i,j).*B(i,j).*v.*w + ...
                   (B(i,j).*w).^2);
            = sum((A(i,j).*v).^2 + ...
                  2.*A(i,j).*B(i,j).*v.*w + ...
                  (B(i,j).*w).^2)/d;
            = sum((A(i,j).*v).^2)/d + ...
              sum(2.*A(i,j).*B(i,j).*v.*w)/d + ...
              sum((B(i,j).*w).^2)/d;
            = A(i,j).^2.*mean(v.^2) + ...
              2.*A(i,j).*B(i,j).*mean(v.*w) + ...
              B(i,j).^2.*mean(w.^2);
于 2011-06-15T18:59:46.010 に答える
1

Try reshaping the vectors v and w to be 1 x 1 x d:

  mean (bsxfun(@times, A, reshape(v, 1, 1, [])) ...
        + bsxfun(@times, B, reshape(w, 1, 1, [])), 3)

Here I am using [] in the argument to reshape to tell it to fill that dimension in based on the product of all the other dimensions and the total number of elements in the vector.

于 2011-06-15T19:02:40.293 に答える
1

Use repmat to tile the matrix in the third dimension.

A =

     1     2     3
     4     5     6

>> repmat(A, [1 1  10])

ans(:,:,1) =

     1     2     3
     4     5     6


ans(:,:,2) =

     1     2     3
     4     5     6

etc.

于 2011-06-15T19:45:36.483 に答える
1

You still don't have to resort to any explicit loops or indirect looping using bsxfun et al. for your updated requirements. You can achieve what you want by a simple vectorized solution as follows

output = reshape(mean((v(:)*A(:)'+w(:)*B(:)').^2),size(A));

Since OP only says that v and w are vectors of length d, the above solution should work for both row and column vectors. If they are known to be column vectors, v(:) can be replaced by v and likewise for w.


You can check if this matches Lambdageek's answer (modified to square the terms) as follows

outputLG = mean ((bsxfun(@times, A, reshape(v, 1, 1, [])) ...
        + bsxfun(@times, B, reshape(w, 1, 1, []))).^2, 3);

isequal(output,outputLG)

ans =

     1
于 2011-06-15T21:53:08.003 に答える