MATLAB Language
Wektoryzacja
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:
- dwie tablice mają te same wymiary, z wyjątkiem jednej
- 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:
- Dokumentacja MATLAB na temat „ Kompatybilnych rozmiarów tablic dla podstawowych operacji ”.
- NumPy's Broadcasting 1 , 2 .
- Porównanie szybkości obliczeń za pomocą
bsxfun
vs. niejawne rozszerzenie tablicy .
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ść.