Создание и управление трехмерными матрицами в Matlab - PullRequest
6 голосов
/ 15 июня 2011

Я отчаянно пытаюсь избежать цикла for в Matlab, но я не могу понять, как это сделать. Вот ситуация:

У меня есть две m x n матрицы A и B и два вектора v и w длины d. Я хочу умножить A и v, чтобы получить матрицу m x n x d, где запись (i,j,k) равна A_(i,j) * v_k, и аналогично для B и w.

После этого я хочу добавить полученные матрицы m x n x d, а затем взять mean вдоль последнего измерения, чтобы получить матрицу m x n.

Я почти уверен, что справлюсь с последней частью, но первая часть полностью застряла. Я пытался использовать bsxfun безрезультатно. Кто-нибудь знает эффективный способ сделать это? Большое спасибо!

РЕДАКТИРОВАТЬ: Этот пересмотр после трех великих ответов ниже. У gnovice есть лучший ответ на вопрос, который я задал без сомнения. Тем не менее, вопрос, который я хотел задать, включает в себя квадрат каждой записи перед тем, как взять среднее. Я забыл упомянуть эту часть изначально. Учитывая эту досаду, оба других ответа работают хорошо, но умный прием алгебры перед кодированием на этот раз не помогает. Всем спасибо за помощь!

Ответы [ 4 ]

7 голосов
/ 15 июня 2011

РЕДАКТИРОВАТЬ:

Несмотря на то, что проблема в вопросе была обновлена, алгебраический подход все еще может быть использован для упрощения вопросов.Вам все еще не нужно возиться с трехмерными матрицами.Ваш результат будет следующим:

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

Если ваши матрицы и векторы большие, это решение даст вам гораздо лучшую производительность из-за уменьшения объема памяти, необходимого по сравнению с решениями, использующими BSXFUN или REPMAT .


Объяснение:

Предполагается, что M является m-by-n-by-d Матрица, которую вы получаете в результате, прежде чем взять среднее значение по третьему измерению, это то, что будет содержать промежуток по третьему измерению:

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

Другими словами, вектор v масштабируется по A(i,j) плюс вектор w, масштабированный до B(i,j).И это то, что вы получаете, когда применяете поэлементное возведение в квадрат:

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;

Теперь, когда вы берете среднее значение по третьему измерению, результат для каждого элемента output(i,j) будет следующим:

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);
1 голос
/ 16 июня 2011

Вам все еще не нужно прибегать к каким-либо явным циклам или косвенным циклам, используя bsxfun и др. .для ваших обновленных требований.Вы можете достичь желаемого с помощью простого векторизованного решения следующим образом:

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

Поскольку OP только говорит, что v и w - это векторы длины d, приведенное выше решение должно работать для обеих строк.и векторы столбцов.Если известно, что они являются векторами столбцов, v(:) можно заменить на v, а также на w.


Вы можете проверить, соответствует ли это ответ Lambdageek (изменено, чтобы возвести в квадрат термины) следующим образом

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

isequal(output,outputLG)

ans =

     1
1 голос
/ 15 июня 2011

Используйте repmat, чтобы расположить матрицу в третьем измерении.

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

и т. Д.

1 голос
/ 15 июня 2011

Попробуйте изменить векторы v и w, чтобы они были 1 x 1 x d:

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

Здесь я использую [] в аргументе reshape, чтобы сказать ему заполнить это измерениев расчете на произведение всех других измерений и общего количества элементов в векторе.

...