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:

  1. Dos matrices comparten las mismas dimensiones excepto una
  2. 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:

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.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow