2016-02-22 19 views
7

Ecco quello che vorrei realizzare:estendere un 2D-matrice per un 3D-matrice moltiplicando con un vettore

ho una matrice C

C=[1 2 3; 4 5 6; 7 8 9]; 

E un vettore a

a=[1 2]; 

Vorrei eseguire un'operazione di questo tipo, che ogni elemento del vettore a venga moltiplicato con C (moltiplicazione scalare) e che venga fornito un 3-dimens ionale serie D:

(:,:,1) = 

    1  2  3 
    4  5  6 
    7  8  9 


(:,:,2) = 

    2  4  6 
    8 10 12 
    14 16 18 

Sarebbe certamente lavorare con un ciclo, ma, dal momento che avrò bisogno di questa operazione in più occasioni, un oneliner sarebbe un grande risparmio.

risposta

6

Alcuni reshape 'ing ed alcuni bsxfun farà:

out = reshape(bsxfun(@mtimes, C(:), a(:).'), [size(C),numel(a)]) 

Come suggerito in hbaderts answer si potrebbe anche usare bsxfun' capacità di espansione dimensione s, e di fornire un vettore permutato di fattori:

out = bsxfun(@mtimes,C,permute(a,[3,1,2])) 

out(:,:,1) = 

    1  2  3 
    4  5  6 
    7  8  9 


out(:,:,2) = 

    2  4  6 
    8 10 12 
    14 16 18 
10

Questo è un bellissimo esempio per l'uso di bsxfun e reshape. Mentre @thewaywewalks propone la prima chiamata bsxfun e il rimodellamento del risultato, suggerirei il contrario. Questo rende uno dei concetti chiave della bsxfun - l'espansione Singleton dimensione - più chiaro:

out = bsxfun(@times,C,reshape(a,1,1,[])) 

ans(:,:,1) = 

    1  2  3 
    4  5  6 
    7  8  9 


ans(:,:,2) = 

    2  4  6 
    8 10 12 
    14 16 18 

Con reshape(a,1,1,[]), fate a essere nella terza dimensione. Se si applica ora bsxfun, moltiplica la matrice C con ogni elemento di a.

+3

Non sarebbe 'permute' essere più adatto di' rimodellare qui? – Dan

4

EDIT (benchmarking): Dato che diverse soluzioni (compreso il mio) di seguito sono state suggerite, ecco alcune analisi comparativa di massima per confrontare le diverse soluzioni, utilizzando gli array più grandi:

a=1:10; 
N=1000; timers=zeros(N,6); 
for ii=1:N; C=rand(400); 
    tic; out = repmat(C,[1,1,numel(a)]).*reshape(repelem(a,size(C,1),size(C,2)),[size(C),numel(a)]); timers(ii,1)=toc; 
    tic; out = bsxfun(@times,C,reshape(a,1,1,[])); timers(ii,2)=toc; 
    tic; out = reshape(C(:)*a, size(C,1), size(C,2), numel(a)); timers(ii,3)=toc; 
    tic; out = bsxfun(@mtimes,C,permute(a,[3,1,2])); timers(ii,4)=toc; 
    tic; out = reshape(bsxfun(@mtimes, C(:), a(:).'), [size(C),numel(a)]); timers(ii,5)=toc; 
    tic; out = reshape(kron(a,C),[size(C),numel(a)]); timers(ii,6)=toc; 
end; 

mean(timers) 

ans = 

    0.0080863 0.0032406 0.0041718  0.015166 0.0074462 0.0033051 

... suggerendo che La soluzione @hbaderts è la più veloce, quindi @ Adiel's, poi @Luis Mendo's, poi @ thewaywewalk's (1), poi la mia, poi @ thewaywewalk's (2).

mia soluzione:

Un'altra opzione, utilizzando repmat e reshape (senza bsxfun):

out = repmat(C,[1,1,numel(a)]).*reshape(repelem(a,size(C,1),size(C,2)),[size(C),numel(a)]) 

out(:,:,1) = 

1  2  3 
4  5  6 
7  8  9 

out(:,:,2) = 

2  4  6 
8 10 12 
14 16 18 

Questa è la moltiplicazione elemento-saggio di due array. Il primo e il matrice originale C ripetuto numel(a) volte nella terza dimensione:

repmat(C,[1,1,numel(a)]) 

ans(:,:,1) = 

1  2  3 
4  5  6 
7  8  9 

ans(:,:,2) = 

1  2  3 
4  5  6 
7  8  9 

Il secondo è la stessa dimensione come prima, con ogni fetta contenente l'elemento corrispondente a:

reshape(repelem(a,size(C,1),size(C,2)),[size(C),numel(a)]) 

ans(:,:,1) = 

1  1  1 
1  1  1 
1  1  1 

ans(:,:,2) = 

2  2  2 
2  2  2 
2  2  2 
4

Un'altra possibilità è quella di utilizzare matrix multiplication di C come vettore di colonna volte a come vettore di riga (questo fornisce tutti i prodotti element-wise), e quindi reshape il risultato:

out = reshape(C(:)*a, size(C,1), size(C,2), numel(a)); 
6

ho un altro metodo per il punto di riferimento confrontare ... IMO è il modo più pulita, almeno per il periodo di sintassi/leggibilità:

out = reshape(kron(a,C),[size(C),numel(a)]); 

out(:,:,1) = 

    1  2  3 
    4  5  6 
    7  8  9 


out(:,:,2) = 

    2  4  6 
    8 10 12 
    14 16 18 
+2

Mi piace, ma 'kron' e leggibilità .... solo se hai qualche background matematico accurato direi! –

+0

Oppure qualche esperienza ininterrotta con quell'utile funzione ... :) – Adiel