MATLAB Language
Vektorisierung
Suche…
Elementweise Operationen
MATLAB unterstützt (und ermutigt) vektorisierte Operationen an Vektoren und Matrizen.
Angenommen, wir haben A
und B
, zwei n
um- m
Matrizen, und wir wollen, dass C
das elementare Produkt der entsprechenden Elemente ist (dh C(i,j) = A(i,j)*B(i,j)
).
Die nicht vektorisierte Methode, verschachtelte Schleifen zu verwenden, lautet wie folgt:
C = zeros(n,m);
for ii=1:n
for jj=1:m
C(ii,jj) = A(ii,jj)*B(ii,jj);
end
end
Die vektorisierte Methode hierfür ist jedoch der elementweise Operator .*
:
C = A.*B;
- Weitere Informationen zur elementweisen Multiplikation in MATLAB finden Sie in der Dokumentation der
times
. - Weitere Informationen über den Unterschied zwischen Arrays und Matrixoperationen siehe Array vs. Matrix - Operationen in der MATLAB - Dokumentation.
Summe, Mittelwert, Prod & Co
Gegeben ein zufälliger Vektor
v = rand(10,1);
Wenn Sie die Summe seiner Elemente wünschen, verwenden Sie KEINE Schleife
s = 0;
for ii = 1:10
s = s + v(ii);
end
Verwenden Sie jedoch die vektorisierte Funktion der Funktion sum()
s = sum(v);
Funktionen wie sum()
, mean()
, prod()
und andere können direkt entlang von Zeilen, Spalten oder anderen Dimensionen arbeiten.
Zum Beispiel eine zufällige Matrix gegeben
A = rand(10,10);
Der Durchschnitt für jede Spalte ist
m = mean(A,1);
Der Durchschnitt für jede Zeile ist
m = mean(A,2)
Alle oben genannten Funktionen funktionieren nur in einer Dimension, aber was ist, wenn Sie die gesamte Matrix summieren möchten? Du könntest benutzen:
s = sum(sum(A))
Aber was wäre, wenn ich ein ND-Array habe? Anwendung sum
auf sum
auf sum
... scheint nicht wie die beste Option, verwenden Sie stattdessen den :
Betreiber Array vektorisieren:
s = sum(A(:))
und dies ergibt eine Zahl, die die Summe Ihres Arrays ist, egal wie viele Dimensionen es hat.
Verwendung von bsxfun
Der Grund, warum Code in eine for
Schleife geschrieben wurde, ist häufig das Berechnen von Werten aus 'nahen' Werten. Die Funktion bsxfun
kann häufig dazu verwendet werden.
Nehmen Sie beispielsweise an, Sie möchten eine spaltenweise Operation an der Matrix B
ausführen und den Mittelwert jeder Spalte davon abziehen:
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
Diese Methode ist ineffizient, wenn B
groß ist. Dies liegt häufig daran, dass MATLAB den Inhalt von Variablen im Speicher verschieben muss. Durch die Verwendung von bsxfun
können Sie dieselbe Aufgabe in nur einer Zeile ordentlich und problemlos erledigen:
A = bsxfun(@minus, B, mean(B));
Hier @minus
ist ein Funktionsgriff zum minus
Operator ( -
) und zwischen den Elementen der beiden Matrizen angewendet werden B
und mean(B)
, mean(B)
. Andere Funktionshandles, auch benutzerdefinierte, sind ebenfalls möglich.
Angenommen, Sie möchten der Zeile A
in Matrix A
Zeilenvektor v
hinzufügen:
v = [1, 2, 3];
A = [8, 1, 6
3, 5, 7
4, 9, 2];
Der naive Ansatz ist eine Schleife ( mach das nicht ):
B = zeros(3);
for row = 1:3
B(row,:) = A(row,:) + v;
end
Eine weitere Option wäre zu replizieren v
mit repmat
(nicht tut dies entweder):
>> v = repmat(v,3,1)
v =
1 2 3
1 2 3
1 2 3
>> B = A + v;
Verwenden bsxfun
stattdessen bsxfun
für diese Aufgabe:
>> B = bsxfun(@plus, A, v);
B =
9 3 9
4 7 10
5 11 5
Syntax
bsxfun(@fun, A, B)
Dabei ist @fun
eine der unterstützten Funktionen und die beiden Arrays A
und B
@fun
die beiden folgenden Bedingungen.
Der Name bsxfun
hilft zu verstehen , wie die Funktion arbeitet und es steht für B inary FUN ction mit S ingleton e X pansion. Mit anderen Worten, wenn:
- Zwei Arrays haben die gleichen Abmessungen außer einem
- und die diskordante Dimension ist in jedem der beiden Arrays ein Singleton (dh hat eine Größe von
1
)
Dann wird das Array mit der Singleton-Dimension erweitert, um der Dimension des anderen Arrays zu entsprechen. Nach der Erweiterung wird eine binäre Funktion elementweise auf die beiden Arrays angewendet.
Zum Beispiel sei A
ein M
by- N
by K
Array und B
ist ein M
by- N
Array. Erstens haben ihre ersten beiden Dimensionen entsprechende Größen. Zweitens hat A
K
Schichten, während B
implizit nur 1
, daher ist es ein Singleton. Alle Bedingungen sind erfüllt und B
wird entsprechend der 3. Dimension von A
repliziert.
In anderen Sprachen wird dies häufig als Rundfunk bezeichnet und geschieht automatisch in Python (Numpy) und Octave.
Die Funktion @fun
muss eine binäre Funktion sein, dh sie muss genau zwei Eingaben annehmen.
Bemerkungen
Intern repliziert bsxfun
das Array nicht und führt eine effiziente Schleife aus.
Logische Maskierung
MATLAB unterstützt die Verwendung der logischen Maskierung, um die Auswahl in einer Matrix ohne for-Schleifen oder if-Anweisungen auszuführen.
Eine logische Maske ist als eine Matrix definiert, die nur aus 1
und 0
.
Zum Beispiel:
mask = [1 0 0; 0 1 0; 0 0 1];
ist eine logische Matrix, die die Identitätsmatrix darstellt.
Wir können eine logische Maske mit einem Prädikat zum Abfragen einer Matrix generieren.
A = [1 2 3; 4 5 6; 7 8 9];
B = A > 4;
Zuerst erstellen wir eine 3x3-Matrix A
, die die Zahlen 1 bis 9 enthält. Wir fragen dann A
nach Werten ab, die größer als 4 sind, und speichern das Ergebnis in einer neuen Matrix mit dem Namen B
B
ist eine logische Matrix der Form:
B = [0 0 0
0 1 1
1 1 1]
Oder 1
wenn das Prädikat A > 4
wahr ist. Und 0
wenn es falsch war.
Wir können logische Matrizen verwenden, um auf Elemente einer Matrix zuzugreifen. Wenn eine logische Matrix zum Auswählen von Elementen verwendet wird, werden in der Matrix, aus der Sie auswählen, Indizes ausgewählt, bei denen eine 1
in der logischen Matrix angezeigt wird.
Mit demselben B
von oben könnten wir Folgendes tun:
C = [0 0 0; 0 0 0; 0 0 0];
C(B) = 5;
Dies würde alle Elemente von C
auswählen, bei denen B
eine 1
in diesem Index hat. Diese Indizes in C
werden dann auf 5
.
Unser C
sieht jetzt so aus:
C = [0 0 0
0 5 5
5 5 5]
Wir können komplizierte Codeblöcke reduzieren, die if
und for
indem Sie logische Masken verwenden.
Nehmen Sie den nicht vektorisierten Code:
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
Dies kann durch logisches Maskieren zu folgendem Code verkürzt werden:
A = [1 3 5; 7 9 11; 11 9 7];
B = A > 5;
A(B) = A(B) - 2;
Oder noch kürzer:
A = [1 3 5; 7 9 11; 11 9 7];
A(A > 5) = A(A > 5) - 2;
Implizite Array-Erweiterung (Broadcasting) [R2016b]
In MATLAB R2016b wurde der Mechanismus der skalaren Erweiterung 1 , 2 verallgemeinert, um auch bestimmte elementweise Operationen zwischen Arrays unterschiedlicher Größe zu unterstützen, sofern ihre Abmessungen kompatibel sind. Die Operatoren, die die implizite Erweiterung unterstützen, sind 1 :
- Elementweise arithmetische Operatoren:
+
,-
./
.*
./
.^
,./
.\
. - Vergleichsoperatoren:
<
,<=
,>
,>=
,==
,~=
. - Logische Operatoren:
&
,|
xor
. - Bitweise Funktionen:
bitand
,bitor
,bitxor
. - Mathematische Grundfunktionen:
max
,min
,mod
,rem
,hypot
,atan2
,atan2d
.
Die zuvor genannten binären Operationen sind zwischen Arrays zulässig, sofern sie "kompatible Größen" haben. Größen werden als "kompatibel" betrachtet, wenn jede Dimension in einem Array entweder genau gleich ist wie das andere Array oder gleich 1
. Beachten Sie, dass nachgestellte Singleton-Dimensionen (d. H. Von Größe 1
) von MATLAB weggelassen werden, obwohl theoretisch unendlich viele vorhanden sind. Mit anderen Worten: Dimensionen, die in einem Array erscheinen und nicht im anderen Array erscheinen, sind implizit für die automatische Erweiterung geeignet.
In MATLAB-Versionen vor R2016b wäre dies beispielsweise der Fall:
>> magic(3) + (1:3)
Error using +
Matrix dimensions must agree.
Ab R2016b wird die vorherige Operation erfolgreich sein:
>> magic(3) + (1:3)
ans =
9 3 9
4 7 10
5 11 5
Beispiele für kompatible Größen:
Beschreibung | 1. Array - Größe | 2. Array - Größe | Ergebnisgröße |
---|---|---|---|
Vektor und Skalar | [3x1] | [1x1] | [3x1] |
Zeilen- und Spaltenvektoren | [1x3] | [2x1] | [2x3] |
Vektor- und 2D-Matrix | [1x3] | [5x3] | [5x3] |
ND- und KD-Arrays | [1x3x3] | [5x3x1x4x2] | [5x3x3x4x2] |
Beispiele für inkompatible Größen:
Beschreibung | 1. Array - Größe | 2. Array - Größe | Mögliche Problemumgehung |
---|---|---|---|
Vektoren, bei denen eine Dimension ein Vielfaches derselben Dimension im anderen Array ist. | [1x2] | [1x8] | transpose |
Arrays mit Dimensionen, die ein Vielfaches voneinander sind. | [2x2] | [8x8] | repmat , reshape |
ND-Arrays mit der richtigen Menge an Singleton-Abmessungen, aber in der falschen Reihenfolge (# 1). | [2x3x4] | [2x4x3] | permute |
ND-Arrays mit der richtigen Menge an Singleton-Abmessungen, aber in der falschen Reihenfolge (# 2). | [2x3x4x5] | [5x2] | permute |
WICHTIG:
Code auf dieser Konvention unter Berufung ist nicht rückwärtskompatibel mit allen älteren Versionen von MATLAB. Daher sollte der explizite Aufruf von bsxfun
1 , 2 (mit dem gleichen Effekt) verwendet werden, wenn Code unter älteren MATLAB-Versionen ausgeführt werden muss. Wenn ein solches bsxfun
nicht besteht, bsxfun
MATLAB R2016- bsxfun
den Benutzer, von bsxfun
zu wechseln:
Im Vergleich zur Verwendung von
bsxfun
bietet die implizite Erweiterung eine schnellere Ausführung, eine bessere Speichernutzung und eine verbesserte Lesbarkeit des Codes.
Verwandte Lesung:
- MATLAB-Dokumentation zu " Kompatible Array-Größen für grundlegende Operationen ".
- NumPy's Broadcasting 1 , 2 .
- Ein Vergleich zwischen der Rechengeschwindigkeit mit
bsxfun
und der impliziten Array-Erweiterung .
Rufen Sie den Wert einer Funktion von zwei oder mehr Argumenten ab
In vielen Anwendungen ist es notwendig, die Funktion von zwei oder mehr Argumenten zu berechnen.
Traditionell verwenden wir for
-loops. Wenn Sie beispielsweise f = exp(-x^2-y^2)
berechnen müssen (verwenden Sie dies nicht, wenn Sie schnelle Simulationen benötigen):
% 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
Die vektorisierte Version ist jedoch eleganter und schneller:
% code2
[x,y] = ndgrid(-1.2:0.2:1.4, -2:0.25:3);
f = exp(-x.^2-y.^2);
als wir es uns vorstellen können:
surf(x,y,f)
Hinweis 1 - Raster : Normalerweise ist der Matrixspeicher Zeile für Zeile organisiert . In MATLAB ist dies jedoch die spaltenweise Speicherung wie in FORTRAN. Daher gibt es in MATLAB zwei Simelfunktionen, nämlich ndgrid
und meshgrid
, um die beiden zuvor genannten Modelle zu implementieren. Um die Funktion im Fall von meshgrid
zu visualisieren, können wir meshgrid
verwenden:
surf(y,x,f)
Hinweis2 - Speicherverbrauch: Die Größe von x
oder y
1000 sein. Daher müssen wir 1000*1000+2*1000 ~ 1e6
Elemente für nicht vektorisierten Code1 speichern . Bei vektorisiertem Code2 benötigen wir jedoch 3*(1000*1000) = 3e6
Elemente. Im 3D-Fall ( z
B. hat dieselbe Größe wie x
oder y
) steigt der Speicherverbrauch dramatisch: 4*(1000*1000*1000)
(~ 32 GB für Doubles) im Fall des vektorisierten Codes2 im Vergleich zu ~1000*1000*1000
(nur ~ 8 GB) im Fall von Code1 . Daher müssen wir entweder den Speicher oder die Geschwindigkeit wählen.