MATLAB Language
Vectorización
Buscar..
Operaciones de elementos sabios
MATLAB apoya (y alienta) operaciones vectorizadas en vectores y matrices.
Por ejemplo, supongamos que tenemos A
y B
, dos matrices n
by- m
y queremos que C
sea el producto de los elementos correspondientes (es decir, C(i,j) = A(i,j)*B(i,j)
).
La forma no vectorizada, utilizando bucles anidados es la siguiente:
C = zeros(n,m);
for ii=1:n
for jj=1:m
C(ii,jj) = A(ii,jj)*B(ii,jj);
end
end
Sin embargo, la forma vectorizada de hacerlo es mediante el uso de un operador de elementos .*
:
C = A.*B;
- Para obtener más información sobre la multiplicación de elementos en MATLAB, consulte la documentación de
times
. - Para obtener más información sobre la diferencia entre las operaciones de matriz y matriz, consulte Operaciones de matriz frente a Matriz en la documentación de MATLAB.
Suma, media, prod & co
Dado un vector aleatorio
v = rand(10,1);
Si desea la suma de sus elementos, NO use un bucle
s = 0;
for ii = 1:10
s = s + v(ii);
end
pero usa la capacidad vectorizada de la función sum()
s = sum(v);
Las funciones como sum()
, mean()
, prod()
y otras, tienen la capacidad de operar directamente a lo largo de filas, columnas u otras dimensiones.
Por ejemplo, dada una matriz aleatoria.
A = rand(10,10);
el promedio para cada columna es
m = mean(A,1);
el promedio para cada fila es
m = mean(A,2)
Todas las funciones anteriores solo funcionan en una dimensión, pero ¿qué sucede si desea sumar toda la matriz? Podrías usar:
s = sum(sum(A))
Pero, ¿qué pasa si tengo una matriz ND? aplicando sum
en sum
en sum
... no parece la mejor opción, en su lugar use el operador :
para vectorizar su matriz:
s = sum(A(:))
y esto resultará en un número que es la suma de toda tu matriz, no importa cuántas dimensiones tenga.
Uso de bsxfun
Muy a menudo, la razón por la que el código se ha escrito en un bucle for
es para calcular valores de valores "cercanos". La función bsxfun
se puede usar para hacer esto de una manera más sucinta.
Por ejemplo, suponga que desea realizar una operación de columnas en la matriz B
, restando de ella la media de cada columna:
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
Este método es ineficiente si B
es grande, a menudo debido a que MATLAB tiene que mover el contenido de las variables en la memoria. Al usar bsxfun
, uno puede hacer el mismo trabajo de forma clara y sencilla en una sola línea:
A = bsxfun(@minus, B, mean(B));
Aquí, @minus
es un controlador de función para el operador minus
( -
) y se aplicará entre los elementos de las dos matrices B
y la mean(B)
. También son posibles otros manejadores de función, incluso los definidos por el usuario.
A continuación, suponga que desea agregar el vector de fila v
a cada fila de la matriz A
:
v = [1, 2, 3];
A = [8, 1, 6
3, 5, 7
4, 9, 2];
El enfoque ingenuo es usar un bucle ( no hacer esto ):
B = zeros(3);
for row = 1:3
B(row,:) = A(row,:) + v;
end
Otra opción sería replicar v
con repmat
( tampoco haga esto ):
>> v = repmat(v,3,1)
v =
1 2 3
1 2 3
1 2 3
>> B = A + v;
En su lugar, use bsxfun
para esta tarea:
>> B = bsxfun(@plus, A, v);
B =
9 3 9
4 7 10
5 11 5
Sintaxis
bsxfun(@fun, A, B)
donde @fun
es una de las funciones admitidas y las dos matrices A
y B
respetan las dos condiciones a continuación.
El nombre bsxfun
ayuda a entender cómo funciona la función y que representa B cción FUN ciertas piezas con S ingleton e X pansión. En otras palabras, si:
- Dos matrices comparten las mismas dimensiones excepto una
- y la dimensión discordante es un singleton (es decir, tiene un tamaño de
1
) en cualquiera de las dos matrices
luego la matriz con la dimensión singleton se expandirá para coincidir con la dimensión de la otra matriz. Después de la expansión, una función binaria se aplica elementwise en los dos arreglos.
Por ejemplo, sea A
una matriz M
-by- N
-by K
y B
es una matriz M
-by- N
En primer lugar, sus dos primeras dimensiones tienen tamaños correspondientes. En segundo lugar, A
tiene K
capas, mientras que B
tiene implícitamente solo 1
, por lo que es un singleton. Se cumplen todas las condiciones y B
se replicará para coincidir con la tercera dimensión de A
En otros idiomas, esto se conoce comúnmente como transmisión y ocurre automáticamente en Python (numpy) y Octave.
La función, @fun
, debe ser una función binaria, lo que significa que debe tener exactamente dos entradas.
Observaciones
Internamente, bsxfun
no replica la matriz y ejecuta un bucle eficiente.
Enmascaramiento logico
MATLAB admite el uso de enmascaramiento lógico para realizar la selección en una matriz sin el uso de bucles for o enunciados if.
Una máscara lógica se define como una matriz compuesta de solo 1
y 0
.
Por ejemplo:
mask = [1 0 0; 0 1 0; 0 0 1];
Es una matriz lógica que representa la matriz de identidad.
Podemos generar una máscara lógica utilizando un predicado para consultar una matriz.
A = [1 2 3; 4 5 6; 7 8 9];
B = A > 4;
Primero creamos una matriz de 3x3, A
, que contiene los números del 1 al 9. Luego buscamos en A
valores que son mayores que 4 y almacenamos el resultado en una nueva matriz llamada B
B
es una matriz lógica de la forma:
B = [0 0 0
0 1 1
1 1 1]
O 1
cuando el predicado A > 4
era verdadero. Y 0
cuando era falso.
Podemos usar matrices lógicas para acceder a elementos de una matriz. Si se utiliza una matriz lógica para seleccionar elementos, se seleccionarán los índices en los que aparece un 1
en la matriz lógica en la matriz que se está seleccionando.
Usando la misma B
de arriba, podríamos hacer lo siguiente:
C = [0 0 0; 0 0 0; 0 0 0];
C(B) = 5;
Esto seleccionaría todos los elementos de C
donde B
tiene un 1
en ese índice. Los índices en C
se ajustan a 5
.
Nuestra C
ahora se ve como:
C = [0 0 0
0 5 5
5 5 5]
Podemos reducir los bloques de código complicados que contienen if
y for
uso de máscaras lógicas.
Toma el código no vectorizado:
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
Esto se puede acortar utilizando el enmascaramiento lógico al siguiente código:
A = [1 3 5; 7 9 11; 11 9 7];
B = A > 5;
A(B) = A(B) - 2;
O incluso más corto:
A = [1 3 5; 7 9 11; 11 9 7];
A(A > 5) = A(A > 5) - 2;
Expansión de matriz implícita (difusión) [R2016b]
MATLAB R2016b presentó una generalización de su mecanismo de expansión escalar 1 , 2 , para admitir también ciertas operaciones de elementos entre matrices de diferentes tamaños, siempre que su dimensión sea compatible. Los operadores que soportan la expansión implícita son 1 :
- Operadores aritméticos elemento a elemento:
+
,-
,.*
,.^
,./
,.\
. - Operadores relacionales:
<
,<=
,>
,>=
,==
,~=
. - Operadores lógicos:
&
,|
,xor
. - Funciones de bit-bit:
bitand
,bitor
,bitxor
. - Funciones matemáticas elementales:
max
,min
,mod
,rem
,hypot
,atan2
,atan2d
.
Las operaciones binarias mencionadas anteriormente están permitidas entre matrices, siempre que tengan "tamaños compatibles". Los tamaños se consideran "compatibles" cuando cada dimensión en una matriz es exactamente igual a la misma dimensión en la otra matriz, o es igual a 1
. Tenga en cuenta que MATLAB omite las dimensiones finales de singleton (es decir, de tamaño 1
), aunque en teoría hay una cantidad infinita de ellas. En otras palabras, las dimensiones que aparecen en una matriz y no aparecen en la otra, se ajustan implícitamente a la expansión automática.
Por ejemplo, en las versiones de MATLAB anteriores a R2016b, esto sucedería:
>> magic(3) + (1:3)
Error using +
Matrix dimensions must agree.
Considerando que a partir de R2016b la operación anterior tendrá éxito:
>> magic(3) + (1:3)
ans =
9 3 9
4 7 10
5 11 5
Ejemplos de tamaños compatibles:
Descripción | 1er tamaño de la matriz | 2do tamaño de la matriz | Tamaño del resultado |
---|---|---|---|
Vector y escalar | [3x1] | [1x1] | [3x1] |
Vectores de fila y columna | [1x3] | [2x1] | [2x3] |
Vector y matriz 2D | [1x3] | [5x3] | [5x3] |
Arreglos ND y KD | [1x3x3] | [5x3x1x4x2] | [5x3x3x4x2] |
Ejemplos de tamaños incompatibles:
Descripción | 1er tamaño de la matriz | 2do tamaño de la matriz | Posible solución |
---|---|---|---|
Vectores donde una dimensión es un múltiplo de la misma dimensión en la otra matriz. | [1x2] | [1x8] | transpose |
Arreglos con dimensiones que son múltiplos entre sí. | [2x2] | [8x8] | repmat , reshape |
Arrays de ND que tienen la cantidad correcta de dimensiones singleton pero están en el orden incorrecto (# 1). | [2x3x4] | [2x4x3] | permute |
Arrays ND que tienen la cantidad correcta de dimensiones singleton pero están en el orden incorrecto (# 2). | [2x3x4x5] | [5x2] | permute |
IMPORTANTE:
Código confiar en esta convención no es compatible hacia atrás con alguna versión anterior de MATLAB. Por lo tanto, la invocación explícita de bsxfun
1 , 2 (que logra el mismo efecto) debe usarse si el código necesita ejecutarse en versiones anteriores de MATLAB. Si no existe tal preocupación, las notas de la versión de MATLAB R2016 animan a los usuarios a cambiar de bsxfun
:
En comparación con el uso de
bsxfun
, la expansión implícita ofrece una velocidad de ejecución más rápida, un mejor uso de la memoria y una mejor legibilidad del código.
Lectura relacionada:
- Documentación de MATLAB sobre " Tamaños de matriz compatibles para operaciones básicas ".
- NumPy Broadcasting 1 , 2 .
- Una comparación entre la velocidad de computación usando
bsxfun
contra la expansión de matriz implícita .
Obtener el valor de una función de dos o más argumentos.
En muchas aplicaciones es necesario calcular la función de dos o más argumentos.
Tradicionalmente, utilizamos for
-loops. Por ejemplo, si necesitamos calcular f = exp(-x^2-y^2)
(no use esto si necesita simulaciones rápidas ):
% 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
Pero la versión vectorizada es más elegante y más rápida:
% code2
[x,y] = ndgrid(-1.2:0.2:1.4, -2:0.25:3);
f = exp(-x.^2-y.^2);
de lo que podemos visualizarlo:
surf(x,y,f)
Nota 1 - Cuadrículas: por lo general, el almacenamiento de matriz se organiza fila por fila . Pero en el MATLAB, es el almacenamiento columna por columna como en FORTRAN. Por lo tanto, hay dos funciones simulares ndgrid
y meshgrid
en MATLAB para implementar los dos modelos mencionados anteriormente. Para visualizar la función en el caso de meshgrid
, podemos utilizar:
surf(y,x,f)
Nota 2 - El consumo de memoria: Que tamaño de x
o y
es 1000. Por lo tanto, necesitamos almacenar 1000*1000+2*1000 ~ 1e6
elementos para Code1 no vectorizado. Pero necesitamos 3*(1000*1000) = 3e6
elementos en el caso de código vectorizado2. En el caso 3D (si z
tiene el mismo tamaño que x
o y
), el consumo de memoria aumenta dramáticamente: 4*(1000*1000*1000)
(~ 32GB para dobles) en el caso del código vectorizado 2 vs ~1000*1000*1000
(solo ~ 8GB) en el caso de code1 . Por lo tanto, tenemos que elegir entre la memoria o la velocidad.