Szukaj…


Operacje elementarne

MATLAB obsługuje (i zachęca) wektoryzowane operacje na wektorach i macierzach.
Załóżmy na przykład, że mamy A i B , dwie macierze n -na- m i chcemy, aby C był iloczynem elementarnym odpowiednich elementów (tj. C(i,j) = A(i,j)*B(i,j) ).

Sposób bez wektoryzacji przy użyciu zagnieżdżonych pętli jest następujący:

C = zeros(n,m);
for ii=1:n
    for jj=1:m
        C(ii,jj) = A(ii,jj)*B(ii,jj);
    end
end

Jednak wektoryzowany sposób polega na użyciu operatora opartego na elementach .* :

C = A.*B;

  • Więcej informacji na temat mnożenia elementarnego w MATLAB znajduje się w dokumentacji times .
  • Aby uzyskać więcej informacji na temat różnicy między operacjami tablicowymi i macierzowymi, zobacz Operacje tablicowe i macierzowe w dokumentacji MATLAB.

Suma, średnia, prod & co

Biorąc pod uwagę losowy wektor

v = rand(10,1);

jeśli chcesz sumę jego elementów, NIE używaj pętli

s = 0;
for ii = 1:10
    s = s + v(ii);
end 

ale użyj wektoryzowanej funkcji funkcji sum()

s = sum(v);

Funkcje takie jak sum() , mean() , prod() i inne, mają możliwość działania bezpośrednio wzdłuż wierszy, kolumn lub innych wymiarów.

Na przykład, biorąc pod uwagę macierz losową

A = rand(10,10);

średnia dla każdej kolumny wynosi

m = mean(A,1);

średnia dla każdego wiersza wynosi

m = mean(A,2)

Wszystkie powyższe funkcje działają tylko w jednym wymiarze, ale co, jeśli chcesz zsumować całą macierz? Możesz użyć:

s = sum(sum(A))

Ale co jeśli macie macierz ND? stosowanie sum sum sum ... nie wydaje się najlepszą opcją, zamiast tego użyj operatora : do wektoryzacji tablicy:

s = sum(A(:))

a to da w wyniku jedną liczbę, która jest sumą całej tablicy, bez względu na to, ile wymiarów ma.

Korzystanie z bsxfun

Dość często powodem, dla którego kod został napisany w pętli for , jest obliczenie wartości z „pobliskich”. Funkcji bsxfun można często użyć w tym celu w bardziej zwięzły sposób.

Załóżmy na przykład, że chcesz wykonać kolumnową operację na macierzy B , odejmując od niej średnią każdej kolumny:

B = round(randn(5)*10);                  % Generate random data 
A = zeros(size(B));                      % Preallocate array
for col = 1:size(B,2);                    % Loop over columns
    A(:,col) = B(:,col) - mean(B(:,col));   % Subtract means 
end 

Ta metoda jest nieefektywna, jeśli B jest duże, często ze względu na to, że MATLAB musi przenosić zawartość zmiennych w pamięci. Korzystając z bsxfun , można wykonać tę samą pracę starannie i łatwo w jednym wierszu:

A = bsxfun(@minus, B, mean(B));

Tutaj @minus jest uchwytem funkcji do operatora minus ( - ) i zostanie zastosowany między elementami dwóch macierzy B i mean(B) . Możliwe są również inne uchwyty funkcji, nawet te zdefiniowane przez użytkownika.


Następnie załóżmy, że chcesz dodać wektor wiersza v do każdego wiersza w macierzy A :

v = [1,  2,  3];

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

Naiwnym podejściem jest użycie pętli ( nie rób tego ):

B = zeros(3);
for row = 1:3
    B(row,:) = A(row,:) + v;
end

Inną opcją byłoby zreplikowanie v pomocą repmat ( nie rób tego też ):

>> v = repmat(v,3,1)
v =
     1     2     3
     1     2     3
     1     2     3

>> B = A + v; 

Zamiast tego użyj bsxfun do tego zadania:

>> B = bsxfun(@plus, A, v);
B =
     9     3     9
     4     7    10
     5    11     5

Składnia

bsxfun(@fun, A, B)

gdzie @fun jest jedną z obsługiwanych funkcji, a dwie tablice A i B spełniają dwa poniższe warunki.

Nazwa bsxfun pomaga zrozumieć, jak działa funkcja i stoi na B inary FUN ction z S Ingleton e X Pansion. Innymi słowy, jeśli:

  1. dwie tablice mają te same wymiary, z wyjątkiem jednej
  2. a niezgodny wymiar to singleton (tzn. ma rozmiar 1 ) w jednym z dwóch układów

wówczas tablica z wymiarem singletonu zostanie rozwinięta, aby pasowała do wymiaru drugiej tablicy. Po rozwinięciu funkcja binarna jest stosowana elementarnie na dwóch tablicach.

Na przykład, niech A będzie tablicą M -by- N -by K a B będzie tablicą M -by- N . Po pierwsze, ich dwa pierwsze wymiary mają odpowiednie rozmiary. Po drugie, A ma warstwy K podczas gdy B ma domyślnie tylko 1 , stąd jest singletonem. Wszystkie warunki są spełnione, a B zostanie zreplikowane, aby pasowało do trzeciego wymiaru A

W innych językach jest to powszechnie nazywane rozgłaszaniem i odbywa się automatycznie w Pythonie (numpy) i Octave.

Funkcja @fun musi być funkcją binarną, co oznacza, że musi przyjąć dokładnie dwa dane wejściowe.

Uwagi

Wewnętrznie bsxfun nie replikuje tablicy i wykonuje wydajną pętlę.

Logiczne maskowanie

MATLAB obsługuje użycie maskowania logicznego w celu wykonania wyboru na macierzy bez użycia pętli for lub instrukcji if.

Maskę logiczną definiuje się jako macierz złożoną tylko z 1 i 0 .

Na przykład:

mask = [1 0 0; 0 1 0; 0 0 1];

jest matrycą logiczną reprezentującą matrycę tożsamości.

Możemy wygenerować maskę logiczną za pomocą predykatu do zapytania do macierzy.

A = [1 2 3; 4 5 6; 7 8 9];
B = A > 4;

Najpierw tworzymy macierz 3x3, A , zawierającą liczby od 1 do 9. Następnie pytamy A o wartości większe niż 4 i zapisujemy wynik w nowej macierzy o nazwie B

B jest logiczną macierzą postaci:

B = [0 0 0
     0 1 1
     1 1 1]

Lub 1 gdy orzeczenie A > 4 było prawdziwe. I 0 gdy było to fałsz.

Możemy użyć macierzy logicznych, aby uzyskać dostęp do elementów macierzy. Jeśli do wyboru elementów zostanie użyta macierz logiczna, wskaźniki, w których 1 pojawi się w macierzy logicznej, zostaną wybrane w macierzy, z której wybierasz.

Używając tego samego B z góry, możemy wykonać następujące czynności:

C = [0 0 0; 0 0 0; 0 0 0];
C(B) = 5;

To wybrałoby wszystkie elementy C gdzie B ma 1 w tym indeksie. Te wskaźniki w C są następnie ustawione na 5 .

Nasze C wygląda teraz następująco:

C = [0 0 0
     0 5 5
     5 5 5]

Możemy zredukować skomplikowane bloki kodu zawierające if i for , stosując maski logiczne.

Weź kod niewektoryzowany:

A = [1 3 5; 7 9 11; 11 9 7];
for j = 1:length(A)
  if A(j) > 5
    A(j) = A(j) - 2;
  end
end

Można to skrócić za pomocą maskowania logicznego do następującego kodu:

A = [1 3 5; 7 9 11; 11 9 7];
B = A > 5;
A(B) = A(B) - 2;

Lub nawet krócej:

A = [1 3 5; 7 9 11; 11 9 7];
A(A > 5) = A(A > 5) - 2;

Rozszerzona macierz (nadawanie) [R2016b]

MATLAB R2016b zawiera uogólnienie mechanizmu rozszerzania skalarnego 1 , 2 , aby również obsługiwać pewne operacje elementarne między tablicami o różnych rozmiarach, o ile ich wymiary są kompatybilne. Operatory, które obsługują domyślną ekspansję, to 1 :

  • Elementarne operatory arytmetyczne: + , - ./ .* ./ .^ , ./ .\ .
  • Operatory relacyjne: < , <= , > , >= , == , ~= .
  • Operatory logiczne: & , | , xor .
  • Funkcje bitand : bitand , bitor , bitxor .
  • Podstawowe funkcje matematyczne: max , min , mod , rem , hypot , atan2 , atan2d .

Wyżej wymienione operacje binarne są dozwolone między tablicami, o ile mają one „kompatybilne rozmiary”. Rozmiary są uważane za „kompatybilne”, gdy każdy wymiar w jednej tablicy jest dokładnie taki sam jak ten sam wymiar w drugiej tablicy lub jest równy 1 . Zauważ, że końcowe wymiary singletonu (czyli rozmiaru 1 ) są pomijane przez MATLAB, nawet jeśli teoretycznie jest ich nieskończona ilość. Innymi słowy - wymiary, które pojawiają się w jednej tablicy i nie pojawiają się w drugiej, domyślnie nadają się do automatycznego rozszerzenia.

Na przykład w wersjach MATLAB przed R2016b tak by się stało:

>> magic(3) + (1:3)
Error using  + 
Matrix dimensions must agree.

Od wersji R2016b poprzednia operacja zakończy się sukcesem:

>> magic(3) + (1:3)
ans =

     9     3     9
     4     7    10
     5    11     5

Przykłady kompatybilnych rozmiarów:

Opis 1 st Array Rozmiar 2 nd Array Rozmiar Rozmiar wyniku
Wektor i skalar [3x1] [1x1] [3x1]
Wektory wierszy i kolumn [1x3] [2x1] [2x3]
Macierz wektorowa i 2D [1x3] [5x3] [5x3]
Tablice ND i KD [1x3x3] [5x3x1x4x2] [5x3x3x4x2]

Przykłady niezgodnych rozmiarów:

Opis 1 st Array Rozmiar 2 nd Array Rozmiar Możliwe obejście
Wektory, w których wymiar jest wielokrotnością tego samego wymiaru w drugiej tablicy. [1x2] [1x8] transpose
Tablice o wymiarach będących wielokrotnościami siebie. [2x2] [8x8] repmat , reshape
Tablice ND, które mają odpowiednią liczbę wymiarów singletonów, ale są w niewłaściwej kolejności (# 1). [2x3x4] [2x4x3] permute
Tablice ND, które mają odpowiednią liczbę wymiarów singletonów, ale są w niewłaściwej kolejności (# 2). [2x3x4x5] [5x2] permute

WAŻNY:
Kod oparty na tej konwencji NIE jest kompatybilny wstecz z żadnymi starszymi wersjami MATLAB. Dlatego jawne wywołanie bsxfun 1 , 2 (które osiąga ten sam efekt) powinno być użyte, jeśli kod musi działać na starszych wersjach MATLAB. Jeśli problem nie istnieje, informacje o wersji MATLAB R2016 zachęcają użytkowników do przejścia z bsxfun :

W porównaniu z użyciem bsxfun , niejawna ekspansja oferuje większą szybkość wykonywania, lepsze wykorzystanie pamięci i lepszą czytelność kodu.


Powiązana lektura:

Uzyskaj wartość funkcji dwóch lub więcej argumentów

W wielu aplikacjach konieczne jest obliczenie funkcji dwóch lub więcej argumentów.

Tradycyjnie używamy for -loops. Na przykład, jeśli musimy obliczyć f = exp(-x^2-y^2) (nie używaj tego, jeśli potrzebujesz szybkich symulacji ):

% code1
x = -1.2:0.2:1.4;
y = -2:0.25:3;
for nx=1:lenght(x)
   for ny=1:lenght(y)
      f(nx,ny) = exp(-x(nx)^2-y(ny)^2);
   end
end

Ale wersja wektoryzowana jest bardziej elegancka i szybsza:

% code2
[x,y] = ndgrid(-1.2:0.2:1.4, -2:0.25:3);
f = exp(-x.^2-y.^2);

niż możemy to sobie wyobrazić:

surf(x,y,f)

Uwaga 1 - Siatki: Zazwyczaj pamięć macierzowa jest uporządkowana rząd po rzędzie . Ale w MATLAB jest to pamięć kolumna po kolumnie, jak w FORTRAN. Tak więc w MATLAB istnieją dwie ndgrid funkcje ndgrid i meshgrid do implementacji dwóch wyżej wymienionych modeli. Aby zwizualizować funkcję w przypadku meshgrid , możemy użyć:

surf(y,x,f)

Uwaga 2 - Zużycie pamięci: Niech rozmiar x lub y wynosi 1000. Dlatego musimy przechowywać 1000*1000+2*1000 ~ 1e6 elementów dla kodu niewektoryzowanego1 . Ale potrzebujemy 3*(1000*1000) = 3e6 elementów w przypadku kodu wektoryzowanego2. W przypadku 3D (niech z ma ten sam rozmiar co x lub y ) zużycie pamięci gwałtownie wzrasta: 4*(1000*1000*1000) (~ 32 GB dla podwójnych) w przypadku kodu wektoryzowanego 2 vs ~1000*1000*1000 (tylko ~ 8 GB) w przypadku kodu 1 . Dlatego musimy wybrać pamięć lub prędkość.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow