Creare e manipolare le matrici tridimensionali in Matlab
-
28-10-2019 - |
Domanda
Sto disperatamente cercando di evitare un for
Loop in Matlab, ma non riesco a capire come farlo. Ecco la situazione:
ne ho due m x n
matrici A
e B
e due vettori v
e w
di lunghezza d
. Voglio moltiplicare esterno A
e v
in modo da ottenere un m x n x d
matrice dove il (i,j,k)
l'ingresso è A_(i,j) * v_k
, e allo stesso modo per B
e w
.
Successivamente, voglio aggiungere il risultato m x n x d
matrici e poi prendi il mean
Lungo l'ultima dimensione per recuperare un m x n
matrice.
Sono abbastanza sicuro di poter gestire l'ultima parte, ma la prima parte mi ha completamente bloccato. Ho provato a usare bsxfun
inutilmente. Qualcuno sa un modo efficiente per farlo? Grazie mille!
MODIFICARE: Questa revisione arriva dopo le tre grandi risposte di seguito. Gnovice ha la migliore risposta alla domanda che ho posto senza dubbio. Tuttavia, la domanda che intendevo porre implica la quadratura di ogni voce prima di prendere la media. Ho dimenticato di menzionare questa parte in origine. Dato questo fastidio, entrambe le altre risposte funzionano bene, ma il trucco intelligente di fare l'algebra prima della codifica non aiuta questa volta. Grazie per l'aiuto a tutti!
Soluzione
MODIFICARE:
Anche se il problema nella domanda è stato aggiornato, un approccio algebrico può ancora essere utilizzato per semplificare le questioni. Non devi ancora preoccuparti delle matrici 3D. Il tuo risultato sarà solo questo:
output = mean(v.^2).*A.^2 + 2.*mean(v.*w).*A.*B + mean(w.^2).*B.^2;
Se le matrici e i vettori sono grandi, questa soluzione ti darà prestazioni molto migliori a causa della ridotta quantità di memoria richiesta rispetto alle soluzioni che utilizzano Bsxfun o Repmat.
Spiegazione:
Supponendo M
è la matrice m-by-n-by-d che si ottiene di conseguenza prima di prendere la media lungo la terza dimensione, questo è ciò che una durata lungo la terza dimensione conterrà:
M(i,j,:) = A(i,j).*v + B(i,j).*w;
In altre parole, il vettore v
ridimensionato da A(i,j)
più il vettore w
ridimensionato da B(i,j)
. E questo è ciò che ottieni quando applichi una quadratura di elementi:
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;
Ora, quando prendi la media attraverso la terza dimensione, il risultato per ogni elemento output(i,j)
sarà il seguente:
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);
Altri suggerimenti
Prova a rimodellare i vettori v
e w
essere 1 x 1 x d
:
mean (bsxfun(@times, A, reshape(v, 1, 1, [])) ...
+ bsxfun(@times, B, reshape(w, 1, 1, [])), 3)
Qui sto usando []
nell'argomento a reshape
Per dirgli di riempire quella dimensione in base al prodotto di tutte le altre dimensioni e al numero totale di elementi nel vettore.
Uso repmat
per piastrellare la matrice nella terza dimensione.
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
eccetera.
Non devi ancora ricorrere a loop espliciti o ad anello indiretto usando bsxfun
et al. Per i requisiti aggiornati. Puoi ottenere ciò che desideri con una semplice soluzione vettoriale come segue
output = reshape(mean((v(:)*A(:)'+w(:)*B(:)').^2),size(A));
Dal momento che OP lo dice solo v
e w
sono vettori di lunghezza d
, la soluzione sopra dovrebbe funzionare per i vettori di riga e colonna. Se sono noti per essere vettori di colonna, v(:)
può essere sostituito da v
e allo stesso modo per w
.
Puoi verificare se questo corrisponde La risposta di Lambdageek (modificato per quadare i termini) come segue
outputLG = mean ((bsxfun(@times, A, reshape(v, 1, 1, [])) ...
+ bsxfun(@times, B, reshape(w, 1, 1, []))).^2, 3);
isequal(output,outputLG)
ans =
1