Pomnóż matrycę 3D z matrycą 2D

Załóżmy, że mam axbxc macierz X i BXD macierz Y.

Czy istnieje metoda bez pętli, dzięki której mogę mnożyć każdy z C Macierze AxB z Y?

Author: Amro, 2009-11-17

11 answers

Można to zrobić w jednej linii za pomocą funkcji NUM2CELL , aby rozbić macierz X na tablicę komórek i CELLFUN , aby operować między komórkami:

Z = cellfun(@(x) x*Y,num2cell(X,[1 2]),'UniformOutput',false);

Wynikiem Z jest1-by-C tablica komórek, gdzie każda komórka zawieraA-by-D macierz. Jeśli chcesz, aby Z była macierzą A-by-D-by-C, możesz użyć funkcji CAT :

Z = cat(3,Z{:});



Uwaga: moje stare rozwiązanie używane MAT2CELL zamiast NUM2CELL , co nie było tak zwięzłe:

[A,B,C] = size(X);
Z = cellfun(@(x) x*Y,mat2cell(X,A,B,ones(1,C)),'UniformOutput',false);
 15
Author: gnovice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-08 22:22:47

Jako osobiste preferencje, Lubię, aby mój kod był tak zwięzły i czytelny, jak to tylko możliwe.

Oto, co bym zrobił, choć nie spełnia twojego wymogu "no-loops":

for m = 1:C

    Z(:,:,m) = X(:,:,m)*Y;

end

Daje to A x D X C macierz z .

I oczywiście zawsze możesz wstępnie przydzielić Z, aby przyspieszyć działanie za pomocą Z = zeros(A,D,C);.

 16
Author: Zaid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-17 05:28:46

Oto rozwiązanie jednoliniowe (dwa, jeśli chcesz podzielić na 3 Wymiar):

A = 2;
B = 3;
C = 4;
D = 5;

X = rand(A,B,C);
Y = rand(B,D);

%# calculate result in one big matrix
Z = reshape(reshape(permute(X, [2 1 3]), [A B*C]), [B A*C])' * Y;

%'# split into third dimension
Z = permute(reshape(Z',[D A C]),[2 1 3]);

Stąd teraz: Z(:,:,i) zawiera wynik X(:,:,i) * Y


Explanation:

Powyższe może wydawać się mylące, ale pomysł jest prosty. Najpierw biorę trzeci wymiar X i wykonuję pionową konkatenację wzdłuż pierwszego dołka:

XX = cat(1, X(:,:,1), X(:,:,2), ..., X(:,:,C))

... trudność polegała na tym, że C jest zmienną, stąd nie można uogólnić tego wyrażenia za pomocą cat lub vertcat . Następnie mnożymy to przez Y:

ZZ = XX * Y;

W końcu podzieliłem go z powrotem na trzeci wymiar:

Z(:,:,1) = ZZ(1:2, :);
Z(:,:,2) = ZZ(3:4, :);
Z(:,:,3) = ZZ(5:6, :);
Z(:,:,4) = ZZ(7:8, :);

Więc widzisz, że wymaga tylko jednego mnożenia macierzy, ale musisz przekształcić macierz przed i po.

 8
Author: Amro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-17 17:15:50

Zbliżam się do tej samej kwestii, z myślą o najskuteczniejszej metodzie. Istnieją z grubsza trzy podejścia, które widzę wokół, brakuje korzystania z zewnętrznych bibliotek (np. mtimesx):

  1. Pętla przez plastry matrycy 3D
  2. wizardry repmat-and-permute
  3. cellfun mnożenie

Ostatnio porównałem wszystkie trzy metody, aby zobaczyć, która była najszybsza. Moja intuicja była taka, że (2) będzie zwycięzcą. Oto kod:

% generate data
A = 20;
B = 30;
C = 40;
D = 50;

X = rand(A,B,C);
Y = rand(B,D);

% ------ Approach 1: Loop (via @Zaid)
tic
Z1 = zeros(A,D,C);
for m = 1:C
    Z1(:,:,m) = X(:,:,m)*Y;
end
toc

% ------ Approach 2: Reshape+Permute (via @Amro)
tic
Z2 = reshape(reshape(permute(X, [2 1 3]), [A B*C]), [B A*C])' * Y;
Z2 = permute(reshape(Z2',[D A C]),[2 1 3]);
toc


% ------ Approach 3: cellfun (via @gnovice)
tic
Z3 = cellfun(@(x) x*Y,num2cell(X,[1 2]),'UniformOutput',false);
Z3 = cat(3,Z3{:});
toc

Wszystkie trzy podejścia produkowały tę samą moc wyjściową (UFF!), ale o dziwo pętla była najszybsza:

Elapsed time is 0.000418 seconds.
Elapsed time is 0.000887 seconds.
Elapsed time is 0.001841 seconds.

Zauważ, że czasy mogą się znacznie różnić w zależności od próby i czasami (2) wychodzi najwolniej. Różnice te stają się bardziej dramatyczne przy większych danych. Ale z dużo większe DANE, (3) beats (2). Metoda pętli jest nadal najlepsza.

% pretty big data...
A = 200;
B = 300;
C = 400;
D = 500;
Elapsed time is 0.373831 seconds.
Elapsed time is 0.638041 seconds.
Elapsed time is 0.724581 seconds.

% even bigger....
A = 200;
B = 200;
C = 400;
D = 5000;
Elapsed time is 4.314076 seconds.
Elapsed time is 11.553289 seconds.
Elapsed time is 5.233725 seconds.

Ale metoda pętli Może być wolniejsza niż (2), jeśli zapętlony wymiar jest znacznie większy niż i inni

A = 2;
B = 3;
C = 400000;
D = 5;
Elapsed time is 0.780933 seconds.
Elapsed time is 0.073189 seconds.
Elapsed time is 2.590697 seconds.

Więc (2) wygrywa dużym czynnikiem, w tym (może ekstremalnym) przypadku. Może nie istnieje podejście optymalne we wszystkich przypadkach, ale pętla jest nadal całkiem dobra, a w wielu przypadkach najlepsza. Jest również najlepszy pod względem czytelności. Pętla!

 5
Author: Nolan Conaway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-06 22:34:51

Nie. Jest kilka sposobów, ale zawsze wychodzi w pętli, bezpośrednio lub pośrednio.

Żeby zadowolić moją ciekawość, po co ci to w ogóle ?

 1
Author: Rook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-16 22:49:36

Aby odpowiedzieć na pytanie, i dla czytelności, zobacz:

  • W 2013 roku ukazała się jego pierwsza płyta pt.]}

Input

  • 2 tablice
  • dim

Przykład

 nT = 100;
 t = 2*pi*linspace (0,1,nT)’;

 # 2 experiments measuring 3 signals at nT timestamps
 signals = zeros(nT,3,2);
 signals(:,:,1) = [sin(2*t) cos(2*t) sin(4*t).^2];
 signals(:,:,2) = [sin(2*t+pi/4) cos(2*t+pi/4) sin(4*t+pi/6).^2];

 sT(:,:,1) = signals(:,:,1)’;
 sT(:,:,2) = signals(:,:,2)’;
   G = ndmult (signals,sT,[1 2]);

Źródło

Oryginalne źródło. Dodałem komentarze inline.

function M = ndmult (A,B,dim)
  dA = dim(1);
  dB = dim(2);

  # reshape A into 2d
  sA = size (A);
  nA = length (sA);
  perA = [1:(dA-1) (dA+1):(nA-1) nA dA](1:nA);
  Ap = permute (A, perA);
  Ap = reshape (Ap, prod (sA(perA(1:end-1))), sA(perA(end)));

  # reshape B into 2d
  sB = size (B);
  nB = length (sB);
  perB = [dB 1:(dB-1) (dB+1):(nB-1) nB](1:nB);
  Bp = permute (B, perB);
  Bp = reshape (Bp, sB(perB(1)), prod (sB(perB(2:end))));

  # multiply
  M = Ap * Bp;

  # reshape back to original format
  s = [sA(perA(1:end-1)) sB(perB(2:end))];
  M = squeeze (reshape (M, s));
endfunction
 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-08 23:50:31

Gorąco polecam korzystanie z MMX toolbox matlab. Może mnożyć n-wymiarowe macierze tak szybko, jak to możliwe.

Zalety MMX to:

  1. jest to łatwe w użyciu.
  2. mnożenie macierzy N-wymiarowych (w rzeczywistości może mnożyć tablice macierzy 2-D)
  3. wykonuje inne operacje macierzy (transpozycja, mnożenie kwadratowe, rozkład Chola i inne)
  4. używa kompilatora C i wielowątkowe obliczenia dla przyspieszenia.

W przypadku tego problemu wystarczy napisać polecenie:

C=mmx('mul',X,Y);

Oto punkt odniesienia dla wszystkich możliwych metod. Więcej szczegółów można znaleźć w tym pytaniu .

    1.6571 # FOR-loop
    4.3110 # ARRAYFUN
    3.3731 # NUM2CELL/FOR-loop/CELL2MAT
    2.9820 # NUM2CELL/CELLFUN/CELL2MAT
    0.0244 # Loop Unrolling
    0.0221 # MMX toolbox  <===================
 1
Author: Ali Mirzaei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-12 06:06:03

Myślę, że rekurencja, ale to jedyna inna metoda bez pętli, którą możesz wykonać

 0
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-16 22:39:13

Możesz" rozwinąć " pętlę, czyli wypisać sekwencyjnie wszystkie mnożenia, które wystąpią w pętli

 0
Author: µBio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-16 22:42:24

Mam podobne pytanie ale macierz 3D x AxBxC i macierz 2D Y CxD i chcę skończyć z macierzą Danych AxBxD.Wymiary:

A = 30 B = 70 C = 300 D = 100

Macierz 3D, jest zmienną obojętną, która przyjmuje wartość =

1 w każdym wymiarze C w instancjach AxB if (...) (i suma wszystkich Cs = 300), różne dla każdego C.

0 inaczej

Macierz 2-d to dane szeregowe razy.

My największym problemem jest zmienna atrapa.

 0
Author: Tomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-29 16:50:43

Napisałem funkcję ogólnego przeznaczenia do wykonywania dowolnych skurczów tensorowych w Matlabie, używając wewnętrznej funkcji mnożenia macierzy, więc jest bardzo wydajna i równoległa. Jest on dostępny Na FileExchange oraz na github

 0
Author: yohai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-03 15:43:00