MATLAB Language
vectorizeren
Zoeken…
Elementgewijze bewerkingen
MATLAB ondersteunt (en stimuleert) vectorized operaties op vectoren en matrices.
Stel bijvoorbeeld dat we A
en B
, twee n
by- m
matrices en we willen dat C
elementgewijze product is van de overeenkomstige elementen (dwz C(i,j) = A(i,j)*B(i,j)
).
De niet-gevectoriseerde manier, met behulp van geneste lussen is als volgt:
C = zeros(n,m);
for ii=1:n
for jj=1:m
C(ii,jj) = A(ii,jj)*B(ii,jj);
end
end
De gevectoriseerde manier om dit te doen is echter met behulp van de operator voor elementen .*
:
C = A.*B;
- Zie de documentatie over
times
voor meer informatie over de elementgewijze vermenigvuldiging in MATLAB. - Zie Matrixbewerkingen versus matrixbewerkingen in de MATLAB-documentatie voor meer informatie over het verschil tussen matrix- en matrixbewerkingen.
Som, gemiddelde, prod & co
Gegeven een willekeurige vector
v = rand(10,1);
als u de som van de elementen wilt, gebruik dan GEEN lus
s = 0;
for ii = 1:10
s = s + v(ii);
end
maar gebruik de gevectoriseerde mogelijkheid van de functie sum()
s = sum(v);
Functies zoals sum()
, mean()
, prod()
en andere hebben de mogelijkheid om rechtstreeks langs rijen, kolommen of andere dimensies te werken.
Bijvoorbeeld, gegeven een willekeurige matrix
A = rand(10,10);
het gemiddelde voor elke kolom is
m = mean(A,1);
het gemiddelde voor elke rij is
m = mean(A,2)
Alle bovenstaande functies werken slechts op één dimensie, maar wat als u de hele matrix wilt optellen? Je zou kunnen gebruiken:
s = sum(sum(A))
Maar wat als ik een ND-array heb? sum
op sum
op sum
toepassen ... lijkt niet de beste optie, gebruik in plaats daarvan de operator :
om uw array te vectoriseren:
s = sum(A(:))
en dit zal resulteren in één getal dat de som is van al je array, ongeacht hoeveel dimensies het heeft.
Gebruik van bsxfun
Heel vaak is de reden waarom code in een for
lus is geschreven, het berekenen van waarden uit 'nabijgelegen' waarden. De functie bsxfun
kan vaak worden gebruikt om dit op een bsxfun
manier te doen.
Neem bijvoorbeeld aan dat u een kolomgewijze bewerking op de matrix B
wilt uitvoeren, waarbij u het gemiddelde van elke kolom ervan aftrekt:
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
Deze methode is inefficiënt als B
groot is, vaak omdat MATLAB de inhoud van variabelen in het geheugen moet verplaatsen. Door bsxfun
, kan men hetzelfde werk netjes en gemakkelijk doen in slechts een enkele regel:
A = bsxfun(@minus, B, mean(B));
Hier is @minus
een functie- @minus
voor de minus
operator ( -
) en wordt toegepast tussen elementen van de twee matrices B
en mean(B)
. Andere functiehandvatten, zelfs door de gebruiker gedefinieerde, zijn ook mogelijk.
Stel vervolgens dat u rijvector v
aan elke rij in matrix A
wilt toevoegen:
v = [1, 2, 3];
A = [8, 1, 6
3, 5, 7
4, 9, 2];
De naïeve benadering is een lus gebruiken ( doe dit niet ):
B = zeros(3);
for row = 1:3
B(row,:) = A(row,:) + v;
end
Een andere optie zou zijn om te repliceren v
met repmat
(doe dit ook niet te doen):
>> v = repmat(v,3,1)
v =
1 2 3
1 2 3
1 2 3
>> B = A + v;
Gebruik in plaats daarvan bsxfun
voor deze taak:
>> B = bsxfun(@plus, A, v);
B =
9 3 9
4 7 10
5 11 5
Syntaxis
bsxfun(@fun, A, B)
waarbij @fun
een van de ondersteunde functies is en de twee arrays A
en B
de twee onderstaande voorwaarden respecteren.
De naam bsxfun
helpt te begrijpen hoe de functie werkt en het staat voor B inary FUN ction met S ingleton e X pansion. Met andere woorden, als:
- twee arrays delen dezelfde afmetingen, op één na
- en de afwijkende dimensie is een singleton (dwz heeft een grootte van
1
) in een van de twee arrays
dan wordt de array met de singleton-dimensie uitgebreid zodat deze overeenkomt met de dimensie van de andere array. Na de uitbreiding wordt een binaire functie elementair op de twee arrays toegepast.
Laat bijvoorbeeld A
een M
by- N
by K
array zijn en B
is een M
-by- N
array. Ten eerste hebben hun eerste twee dimensies overeenkomstige afmetingen. Ten tweede heeft A
K
lagen, terwijl B
impliciet slechts 1
, vandaar dat het een singleton is. Aan alle voorwaarden is voldaan en B
wordt gerepliceerd om overeen te komen met de 3e dimensie van A
In andere talen wordt dit meestal broadcasting genoemd en gebeurt dit automatisch in Python (numpy) en Octave.
De functie, @fun
, moet een binaire functie zijn, wat betekent dat deze exact twee ingangen moet bevatten.
Opmerkingen
Intern bsxfun
de array niet en voert een efficiënte lus uit.
Logisch maskeren
MATLAB ondersteunt het gebruik van logische maskering om selectie op een matrix uit te voeren zonder het gebruik van for loops of if-instructies.
Een logisch masker wordt gedefinieerd als een matrix die bestaat uit alleen 1
en 0
.
Bijvoorbeeld:
mask = [1 0 0; 0 1 0; 0 0 1];
is een logische matrix die de identiteitsmatrix voorstelt.
We kunnen een logisch masker genereren met behulp van een predikaat om een matrix op te vragen.
A = [1 2 3; 4 5 6; 7 8 9];
B = A > 4;
We maken eerst een 3x3-matrix, A
, met de getallen 1 tot en met 9. We vragen vervolgens A
naar waarden die groter zijn dan 4 en slaan het resultaat op in een nieuwe matrix met de naam B
B
is een logische matrix van de vorm:
B = [0 0 0
0 1 1
1 1 1]
Of 1
toen het predikaat A > 4
waar was. En 0
toen het vals was.
We kunnen logische matrices gebruiken om toegang te krijgen tot elementen van een matrix. Als een logische matrix wordt gebruikt om elementen te selecteren, worden indices waarbij een 1
in de logische matrix verschijnt, geselecteerd in de matrix waaruit u selecteert.
Met dezelfde B
van hierboven kunnen we het volgende doen:
C = [0 0 0; 0 0 0; 0 0 0];
C(B) = 5;
Dit zou alle elementen van C
waar B
een 1
in die index heeft. Die indices in C
worden vervolgens ingesteld op 5
.
Onze C
ziet er nu uit als:
C = [0 0 0
0 5 5
5 5 5]
We kunnen ingewikkelde codeblokken met if
en for
door logische maskers te gebruiken.
Neem de niet-gevectoriseerde 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
Dit kan met logische maskering worden ingekort tot de volgende code:
A = [1 3 5; 7 9 11; 11 9 7];
B = A > 5;
A(B) = A(B) - 2;
Of nog korter:
A = [1 3 5; 7 9 11; 11 9 7];
A(A > 5) = A(A > 5) - 2;
Impliciete array-uitbreiding (uitzending) [R2016b]
MATLAB R2016b bevatte een generalisatie van zijn scalaire uitbreiding 1 , 2- mechanisme, om ook bepaalde elementaire bewerkingen tussen arrays van verschillende grootte te ondersteunen, zolang hun afmetingen compatibel zijn. De operatoren die impliciete uitbreiding ondersteunen zijn 1 :
- Elementgewijze rekenkundige operatoren:
+
,-
./
.*
./
.^
,./
.\
. - Relationele operatoren:
<
,<=
,>
,>=
,==
,~=
. - Logische operatoren:
&
,|
xor
. -
bitand
functies:bitand
,bitor
,bitxor
. - Elementaire wiskundige functies:
max
,min
,mod
,rem
,hypot
,atan2
,atan2d
.
De bovengenoemde binaire bewerkingen zijn toegestaan tussen reeksen, zolang ze "compatibele formaten" hebben. Maten worden als "compatibel" beschouwd wanneer elke dimensie in de ene array exact gelijk is aan dezelfde dimensie in de andere array, of gelijk is aan 1
. Merk op dat de dimensies van singleton (dat wil zeggen, van maat 1
) door MATLAB worden weggelaten, hoewel er in theorie een oneindig aantal is. Met andere woorden - dimensies die in de ene array verschijnen en niet in de andere, zijn impliciet geschikt voor automatische uitbreiding.
In MATLAB-versies vóór R2016b zou dit bijvoorbeeld gebeuren:
>> magic(3) + (1:3)
Error using +
Matrix dimensions must agree.
Terwijl vanaf R2016b de vorige operatie zal slagen:
>> magic(3) + (1:3)
ans =
9 3 9
4 7 10
5 11 5
Voorbeelden van compatibele formaten:
Beschrijving | 1 e matrixgrootte | 2e array-grootte | Resultaatgrootte |
---|---|---|---|
Vector en scalair | [3x1] | [1x1] | [3x1] |
Rij- en kolomvectoren | [1x3] | [2x1] | [2x3] |
Vector- en 2D-matrix | [1x3] | [5x3] | [5x3] |
ND- en KD-arrays | [1x3x3] | [5x3x1x4x2] | [5x3x3x4x2] |
Voorbeelden van incompatibele maten:
Beschrijving | 1 e matrixgrootte | 2e array-grootte | Mogelijke oplossing |
---|---|---|---|
Vectoren waarbij een dimensie een veelvoud is van dezelfde dimensie in de andere array. | [1x2] | [1x8] | transpose |
Arrays met dimensies die veelvouden van elkaar zijn. | [2x2] | [8x8] | repmat , reshape |
ND-arrays die de juiste hoeveelheid singleton-dimensies hebben, maar ze zijn in de verkeerde volgorde (# 1). | [2x3x4] | [2x4x3] | permute |
ND-arrays die de juiste hoeveelheid singleton-dimensies hebben, maar ze zijn in de verkeerde volgorde (# 2). | [2x3x4x5] | [5x2] | permute |
BELANGRIJK:
Code vertrouwen op deze conventie is niet achterwaarts compatibel met alle oudere versies van MATLAB. Daarom moet de expliciete aanroep van bsxfun
1 , 2 (die hetzelfde effect bereikt) worden gebruikt als code moet worden uitgevoerd op oudere MATLAB-versies. Als een dergelijk probleem niet bestaat, moedigen MATLAB R2016 release-opmerkingen gebruikers aan om over te schakelen van bsxfun
:
In vergelijking met het gebruik van
bsxfun
biedt impliciete uitbreiding een snellere uitvoering, beter geheugengebruik en verbeterde leesbaarheid van code.
Gerelateerde lezen:
- MATLAB-documentatie over " Compatibele arrayformaten voor basisbewerkingen ".
- NumPy's uitzending 1 , 2 .
- Een vergelijking tussen de snelheid van computergebruik met
bsxfun
versus impliciete array-uitbreiding .
Krijg de waarde van een functie van twee of meer argumenten
In veel toepassingen is het noodzakelijk om de functie van twee of meer argumenten te berekenen.
Traditioneel gebruiken we for
-loops. Als we bijvoorbeeld de f = exp(-x^2-y^2)
moeten berekenen (gebruik dit niet als u snelle simulaties nodig hebt):
% 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
Maar gevectoriseerde versie is eleganter en sneller:
% code2
[x,y] = ndgrid(-1.2:0.2:1.4, -2:0.25:3);
f = exp(-x.^2-y.^2);
dan kunnen we het visualiseren:
surf(x,y,f)
Opmerking 1 - Rasters: Meestal is de matrixopslag rij voor rij georganiseerd. Maar in het MATLAB is het de kolom voor kolom opslag zoals in FORTRAN. Er zijn dus twee vergelijkbare functies ndgrid
en meshgrid
in MATLAB om de twee bovengenoemde modellen te implementeren. Om de functie in het geval van meshgrid
te visualiseren, kunnen we gebruiken:
surf(y,x,f)
Opmerking 2 - Geheugen verbruik: Laat de grootte van x
of y
is 1000. Daarom moeten we op te slaan 1000*1000+2*1000 ~ 1e6
elementen voor niet-gevectoriseerd code1. Maar we hebben 3*(1000*1000) = 3e6
elementen nodig in het geval van gevectoriseerde code2 . In het 3D-geval (laat z
dezelfde grootte hebben als x
of y
), neemt het geheugenverbruik dramatisch toe: 4*(1000*1000*1000)
(~ 32 GB voor dubbele) in het geval van de gevectoriseerde code2 versus ~1000*1000*1000
(slechts ~ 8GB) in het geval van code1 . We moeten dus het geheugen of de snelheid kiezen.