MATLAB Language
vektorisering
Sök…
Elementvisa operationer
MATLAB stöder (och uppmuntrar) vektoriserade operationer på vektorer och matriser.
Anta till exempel att vi har A
och B
, två n
-by- m
matriser och vi vill att C
att vara det element-wise produkt av de motsvarande elementen (dvs C(i,j) = A(i,j)*B(i,j)
).
Det ovektoriserade sättet med kapslade slingor är som följer:
C = zeros(n,m);
for ii=1:n
for jj=1:m
C(ii,jj) = A(ii,jj)*B(ii,jj);
end
end
Det vektoriserade sättet att göra detta är dock genom att använda den elementmässiga operatören .*
:
C = A.*B;
- För mer information om den elementära multiplikationen i MATLAB se dokumentation av
times
. - För mer information om skillnaden mellan array- och matrisoperationer, se Array vs. Matrix Operations i MATLAB-dokumentationen.
Summa, medel, prod & co
Ges en slumpmässig vektor
v = rand(10,1);
Om du vill ha summan av dess element, använd INTE en slinga
s = 0;
for ii = 1:10
s = s + v(ii);
end
men använd den vektoriserade kapaciteten för sum()
-funktionen
s = sum(v);
Funktioner som sum()
, mean()
, prod()
och andra har förmågan att arbeta direkt längs rader, kolumner eller andra dimensioner.
Till exempel, ges en slumpmässig matris
A = rand(10,10);
genomsnittet för varje kolumn är
m = mean(A,1);
genomsnittet för varje rad är
m = mean(A,2)
Alla funktioner ovan fungerar bara på en dimension, men tänk om du vill summera hela matrisen? Du kan använda:
s = sum(sum(A))
Men tänk om du har en ND-array? tillämpa sum
på sum
på sum
... verkar inte vara det bästa alternativet, använd istället :
operatören för att vektorisera din matris:
s = sum(A(:))
och detta kommer att resultera i ett nummer som är summan av alla dina array, spelar ingen roll hur många dimensioner det har.
Användning av bsxfun
Ofta är orsaken till att kod har skrivits i en for
loop är att beräkna värden från "närliggande". Funktionen bsxfun
kan ofta användas för att göra detta på ett mer kortfattat sätt.
Antag till exempel att du vill utföra en kolumnvis operation på matrisen B
och subtrahera medelvärdet för varje kolumn från den:
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
Denna metod är ineffektiv om B
är stor, ofta på grund av att MATLAB måste flytta innehållet i variabler runt i minnet. Genom att använda bsxfun
kan man göra samma jobb snyggt och enkelt på bara en enda rad:
A = bsxfun(@minus, B, mean(B));
Här är @minus
ett funktionshandtag för minus
( -
) och kommer att appliceras mellan element i de två matriserna B
och mean(B)
. Andra funktionshandtag, även användardefinierade, är också möjliga.
Anta att du vill lägga till radvektor v
till varje rad i matris A
:
v = [1, 2, 3];
A = [8, 1, 6
3, 5, 7
4, 9, 2];
Den naiva metoden är att använda en slinga ( gör inte det här ):
B = zeros(3);
for row = 1:3
B(row,:) = A(row,:) + v;
end
Ett annat alternativ skulle vara att replikera v
med repmat
( gör inte det heller ):
>> v = repmat(v,3,1)
v =
1 2 3
1 2 3
1 2 3
>> B = A + v;
bsxfun
istället bsxfun
för den här uppgiften:
>> B = bsxfun(@plus, A, v);
B =
9 3 9
4 7 10
5 11 5
Syntax
bsxfun(@fun, A, B)
där @fun
är en av de funktioner som stöds och de två matriserna A
och B
respekterar de två villkoren nedan.
Namnet bsxfun
hjälper till att förstå hur funktionen fungerar och den står för B inary FUN ction med S ingleton e X pansion. Med andra ord, om:
- två matriser delar samma dimensioner förutom en
- och den diskordanta dimensionen är en singleton (dvs. har en storlek på
1
) i någon av de två matriserna
sedan utvidgas matrisen med singleton-dimensionen så att den matchar dimensionen för den andra matrisen. Efter utvidgningen appliceras en binär funktion elementvis på de två matriserna.
Till exempel, låt A
vara en M
by- N
by K
grupp och B
är en M
by- N
matris. För det första har deras första två dimensioner motsvarande storlekar. För det andra har A
K
lager medan B
implicit endast har 1
, varför det är en singleton. Alla villkor är uppfyllda och B
kommer att replikeras för att matcha den tredje dimensionen av A
På andra språk benämns detta vanligtvis sändning och sker automatiskt i Python (numpy) och Octave.
Funktionen @fun
måste vara en binär funktion, vilket betyder att den måste ta exakt två ingångar.
Anmärkningar
Internt bsxfun
inte matrisen och kör en effektiv slinga.
Logisk maskering
MATLAB stöder användningen av logisk maskering för att utföra val på en matris utan att använda för slingor eller om uttalanden.
En logisk mask definieras som en matris bestående av endast 1
och 0
.
Till exempel:
mask = [1 0 0; 0 1 0; 0 0 1];
är en logisk matris som representerar identitetsmatrisen.
Vi kan skapa en logisk mask med ett predikat för att fråga en matris.
A = [1 2 3; 4 5 6; 7 8 9];
B = A > 4;
Vi skapar först en 3x3 matris, A
, som innehåller siffrorna 1 till 9. Vi frågar sedan A
för värden som är större än 4 och lagrar resultatet i en ny matris som heter B
B
är en logisk matris av formen:
B = [0 0 0
0 1 1
1 1 1]
Eller 1
när predikatet A > 4
var sant. Och 0
när det var falskt.
Vi kan använda logiska matriser för att komma åt element i en matris. Om en logisk matris används för att välja element, kommer index där en 1
visas i den logiska matrisen att väljas i den matris du väljer från.
Med samma B
ovanifrån kan vi göra följande:
C = [0 0 0; 0 0 0; 0 0 0];
C(B) = 5;
Detta skulle välja alla elementen i C
där B
har en 1
i det indexet. Dessa index i C
ställs sedan in på 5
.
Vår C
ser nu ut:
C = [0 0 0
0 5 5
5 5 5]
Vi kan minska komplicerade kodblock som innehåller if
och for
med logiska masker.
Ta den icke-vektoriserade koden:
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
Detta kan förkortas med logisk maskering till följande kod:
A = [1 3 5; 7 9 11; 11 9 7];
B = A > 5;
A(B) = A(B) - 2;
Eller ännu kortare:
A = [1 3 5; 7 9 11; 11 9 7];
A(A > 5) = A(A > 5) - 2;
Implicit array-expansion (sändning) [R2016b]
MATLAB R2016b innehöll en generalisering av sin skalära expansion 1 , 2- mekanism, för att också stödja vissa elementvisa operationer mellan matriser i olika storlekar, så länge deras dimension är kompatibel. De operatörer som stöder implicit expansion är 1 :
- Elementvisa aritmetiska operatörer:
+
,-
,..*
./
.^
,./
.\
. - Relationsoperatörer:
<
,<=
,>
,>=
,==
,~=
. - Logiska operatörer:
&
,|
,xor
. - Bitvisa funktioner:
bitand
,bitor
,bitxor
. - Elementära matematiska funktioner:
max
,min
,mod
,rem
,hypot
,atan2
,atan2d
.
Ovannämnda binära operationer är tillåtna mellan matriser, så länge de har "kompatibla storlekar". Storlekar betraktas som "kompatibla" när varje dimension i en array antingen är exakt lika med samma dimension i den andra arrayen eller är lika med 1
. Observera att efterföljande singleton-dimensioner (det vill säga av storlek 1
) utelämnas av MATLAB, även om det teoretiskt sett finns en oändlig mängd av dem. Med andra ord - dimensioner som visas i en grupp och inte visas i den andra, är implicit lämpade för automatisk expansion.
Till exempel i MATLAB-versioner före R2016b skulle detta hända:
>> magic(3) + (1:3)
Error using +
Matrix dimensions must agree.
Medan från och med R2016b lyckas den tidigare operationen:
>> magic(3) + (1:3)
ans =
9 3 9
4 7 10
5 11 5
Exempel på kompatibla storlekar:
Beskrivning | 1 st Array Storlek | 2: a matrisstorlek | Resultatstorlek |
---|---|---|---|
Vektor och skalar | [3x1] | [1x1] | [3x1] |
Rad- och kolumnvektorer | [1x3] | [2x1] | [2x3] |
Vektor- och 2D-matris | [1x3] | [5x3] | [5x3] |
ND- och KD-matriser | [1x3x3] | [5x3x1x4x2] | [5x3x3x4x2] |
Exempel på inkompatibla storlekar:
Beskrivning | 1 st Array Storlek | 2: a matrisstorlek | Möjlig lösning |
---|---|---|---|
Vektorer där en dimension är en multipel av samma dimension i den andra matrisen. | [1x2] | [1x8] | transpose |
Matriser med dimensioner som är multiplar av varandra. | [2x2] | [8x8] | repmat , reshape |
ND-matriser som har rätt mängd singleton-dimensioner men de är i fel ordning (nr 1). | [2x3x4] | [2x4x3] | permute |
ND-matriser som har rätt mängd singleton-dimensioner men de är i fel ordning (# 2). | [2x3x4x5] | [5x2] | permute |
VIKTIG:
Kod förlita sig på denna konvention är inte bakåtkompatibel med alla äldre versioner av MATLAB. Därför bsxfun
den uttryckliga åkallandet av bsxfun
1 , 2 (som uppnår samma effekt) användas om koden måste köras på äldre MATLAB-versioner. Om ett sådant problem inte existerar, uppmuntrar MATLAB R2016 utgivningsanmärkningar användare att byta från bsxfun
:
Jämfört med att använda
bsxfun
erbjuder implicit expansion snabbare körningshastighet, bättre minnesanvändning och förbättrad kodbarhet.
Relaterad läsning:
- MATLAB-dokumentation om " Kompatibla matrisstorlekar för grundläggande operationer ".
- NumPys sändning 1 , 2 .
- En jämförelse mellan
bsxfun
hastighet med hjälp avbsxfun
kontra implicit array-expansion .
Få värdet på en funktion av två eller flera argument
I många applikationer är det nödvändigt att beräkna funktionen för två eller flera argument.
Traditionellt använder vi oss for
-loops. Om vi till exempel behöver beräkna f = exp(-x^2-y^2)
(använd inte detta om du behöver snabba simuleringar ):
% 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
Men vektoriserad version är mer elegant och snabbare:
% code2
[x,y] = ndgrid(-1.2:0.2:1.4, -2:0.25:3);
f = exp(-x.^2-y.^2);
än vi kan visualisera det:
surf(x,y,f)
Obs 1 - Raster: Vanligtvis är matrislagret organiserat rad för rad . Men i MATLAB är det kolumn-för-kolumn- lagring som i FORTRAN. Således finns det två simulära funktioner ndgrid
och meshgrid
i MATLAB för att implementera de två ovannämnda modellerna. För att visualisera funktionen i fallet med meshgrid
kan vi använda:
surf(y,x,f)
Note2 - Minneskonsumtion: Låt storleken på x
eller y
1000. Därför måste vi lagra 1000*1000+2*1000 ~ 1e6
element för icke-vektoriserad kod1 . Men vi behöver 3*(1000*1000) = 3e6
element för vektoriserad kod2 . I 3D-fallet (låt z
har samma storlek som x
eller y
) ökar minneskonsumtionen dramatiskt: 4*(1000*1000*1000)
(~ 32 GB för dubbel) när det gäller den vektoriserade koden2 mot ~1000*1000*1000
(bara ~ 8 GB) för kod1 . Därför måste vi välja antingen minne eller hastighet.