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 sumsumsum ... 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:

  1. två matriser delar samma dimensioner förutom en
  2. 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:

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.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow