2016-02-22 46 views
7

Oto, co chciałbym osiągnąć:Rozszerz 2D matrycy do widoku 3D matrycy poprzez pomnożenie wektorem

Mam macierzy C

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

i wektor a

a=[1 2]; 

Chciałbym wykonać taką operację, że każdy element wektora a jest pomnożony przez C (mnożenie skalarne) i wychodzi 3-dimens ional tablica D:

(:,:,1) = 

    1  2  3 
    4  5  6 
    7  8  9 


(:,:,2) = 

    2  4  6 
    8 10 12 
    14 16 18 

Byłoby to na pewno działa z pętlą, ale ponieważ będę potrzebował tej operacji na wielu okazjach, o oneliner byłoby wielkim wygaszacz.

Odpowiedz

6

Niektóre reshape 'ing a niektóre bsxfun zrobi:

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

Jak sugerowano w hbaderts answer można było również skorzystać bsxfun' s możliwości ekspansji wymiar i zapewniają permutacyjny wektor czynników:

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

To jest piękny przykład użycia bsxfun i reshape. Podczas gdy @motywni klienci proponują pierwsze wywołanie bsxfun i zmieniają kształt wyniku, sugeruję coś przeciwnego. To sprawia, że ​​jednym z kluczowych pojęć bsxfun - singleton wymiar ekspansja - bardziej jasne:

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 

Z reshape(a,1,1,[]), robisz a być w trzecim wymiarze. Jeśli teraz zastosujesz bsxfun, pomnożysz macierz C z każdym elementem z a.

+3

Would not 'permute' być bardziej odpowiednie niż' przekształcić "tutaj? – Dan

4

EDIT (benchmark): Ponieważ kilka rozwiązań (w tym kopalni poniżej) zostały zaproponowane, tu jest jakiś szorstki benchmarking porównać różne rozwiązania, używając większych tablic:

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 

... sugeruje, że Rozwiązanie @hbaderts jest najszybsze, następnie @ Adiel, następnie @Luis Mendo, następnie @ thewaywewalk's (1), następnie moje, następnie @ thewaywewalk's (2).

Moje rozwiązanie:

Inną opcją, używając repmat i reshape (bez 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 

Jest to element mnożenie dwóch macierzy. Pierwszym jest oryginalna matryca C powtarzane numel(a) razy w trzecim wymiarze:

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 

drugi jest tego samego rozmiaru jak pierwsza, przy czym każdy plaster zawierający odpowiedni element 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

Inną możliwością jest użycie matrix multiplication z C jako wektora kolumny razy a jako wektora wiersza (daje to wszystkie produkty zgodne z elementami), a następnie reshape wynik:

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

mam inną metodą benchmarku porównać ... IMO to neatest sposób, przynajmniej dla terminu składnia/czytelności:

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

Podoba mi się, ale 'kron' i czytelność .... tylko jeśli masz jakieś czyste tło matematyczne, które powiedziałbym! –

+0

Albo jakieś doświadczenie z tą przydatną funkcją ... :) – Adiel