Puede aplicar una función a cada elemento en un vector diciendo, por ejemplo v + 1
,, o puede usar la función arrayfun
. ¿Cómo puedo hacerlo para cada fila / columna de una matriz sin usar un bucle for?
Puede aplicar una función a cada elemento en un vector diciendo, por ejemplo v + 1
,, o puede usar la función arrayfun
. ¿Cómo puedo hacerlo para cada fila / columna de una matriz sin usar un bucle for?
Respuestas:
Muchas operaciones integradas como sum
y prod
ya pueden operar en filas o columnas, por lo que es posible que pueda refactorizar la función que está aplicando para aprovechar esto.
Si esa no es una opción viable, una forma de hacerlo es recopilar las filas o columnas en celdas usando mat2cell
o num2cell
, luego usar cellfun
para operar en la matriz de celdas resultante.
Como ejemplo, digamos que desea sumar las columnas de una matriz M
. Puede hacer esto simplemente usando sum
:
M = magic(10); %# A 10-by-10 matrix
columnSums = sum(M, 1); %# A 1-by-10 vector of sums for each column
Y así es como lo haría usando la opción num2cell
/ más complicada cellfun
:
M = magic(10); %# A 10-by-10 matrix
C = num2cell(M, 1); %# Collect the columns into cells
columnSums = cellfun(@sum, C); %# A 1-by-10 vector of sums for each cell
true = false
hay una declaración válida, estoy seguro de que hay una forma de hacerlo (:
sum(M, 1)
. Los principiantes pueden pensar que sum
se puede usar de esta manera para matrices de tamaño arbitrario y luego quedar perplejos cuando la matriz lo sea un día 1-by-n
.
Es posible que desee la función bsxfun de Matlab, más oscura . De la documentación de Matlab, bsxfun "aplica la operación binaria elemento por elemento especificada por la función handle fun a las matrices A y B, con la expansión singleton habilitada".
@gnovice indicó anteriormente que la suma y otras funciones básicas ya operan en la primera dimensión que no es singleton (es decir, filas si hay más de una fila, columnas si solo hay una fila, o dimensiones más altas si todas las dimensiones inferiores tienen tamaño == 1 ). Sin embargo, bsxfun funciona para cualquier función, incluidas (y especialmente) las funciones definidas por el usuario.
Por ejemplo, digamos que tiene una matriz A y un vector fila BEg, digamos:
A = [1 2 3;
4 5 6;
7 8 9]
B = [0 1 2]
Quieres una función power_by_col que devuelva en un vector C todos los elementos en A a la potencia de la columna correspondiente de B.
En el ejemplo anterior, C es una matriz de 3x3:
C = [1^0 2^1 3^2;
4^0 5^1 6^2;
7^0 8^1 9^2]
es decir,
C = [1 2 9;
1 5 36;
1 8 81]
Podrías hacer esto por la fuerza bruta usando repmat:
C = A.^repmat(B, size(A, 1), 1)
O puede hacer esto de la manera elegante usando bsxfun, que internamente se encarga del paso repmat:
C = bsxfun(@(x,y) x.^y, A, B)
Entonces, bsxfun le ahorra algunos pasos (no necesita calcular explícitamente las dimensiones de A). Sin embargo, en algunas pruebas informales mías, resulta que repmat es aproximadamente el doble de rápido si la función que se va a aplicar (como mi función de potencia, arriba) es simple. Por lo tanto, deberá elegir si desea simplicidad o velocidad.
No puedo comentar qué tan eficiente es esto, pero aquí hay una solución:
applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :))
applyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1))'
% Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @sum;
applyToRows(myFunc, myMx)
Sobre la base de la respuesta de Alex , aquí hay una función más genérica:
applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :));
newApplyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1), 'UniformOutput', false)';
takeAll = @(x) reshape([x{:}], size(x{1},2), size(x,1))';
genericApplyToRows = @(func, matrix) takeAll(newApplyToRows(func, matrix));
Aquí hay una comparación entre las dos funciones:
>> % Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @(x) [mean(x), std(x), sum(x), length(x)];
>> genericApplyToRows(myFunc, myMx)
ans =
2 1 6 3
5 1 15 3
8 1 24 3
>> applyToRows(myFunc, myMx)
??? Error using ==> arrayfun
Non-scalar in Uniform output, at index 1, output 1.
Set 'UniformOutput' to false.
Error in ==> @(func,matrix)arrayfun(applyToGivenRow(func,matrix),1:size(matrix,1))'
Para completar / interesar, me gustaría agregar que matlab tiene una función que le permite operar con datos por fila en lugar de por elemento. Se llama rowfun
( http://www.mathworks.se/help/matlab/ref/rowfun.html ), pero el único "problema" es que opera en tablas ( http://www.mathworks.se/help/ matlab / ref / table.html ) en lugar de matrices .
Además de la naturaleza evolutiva de la respuesta a esta pregunta, comenzando con r2016b, MATLAB expandirá implícitamente las dimensiones singleton, eliminando la necesidad de bsxfun
en muchos casos.
De las notas de la versión r2016b :
Expansión implícita: aplique operaciones y funciones de elementos a matrices con expansión automática de dimensiones de longitud 1
La expansión implícita es una generalización de la expansión escalar. Con la expansión escalar, un escalar se expande para tener el mismo tamaño que otra matriz para facilitar las operaciones de elementos. Con la expansión implícita, los operadores y las funciones de elementos enumerados aquí pueden expandir implícitamente sus entradas para que tengan el mismo tamaño, siempre que las matrices tengan tamaños compatibles. Dos matrices tienen tamaños compatibles si, para cada dimensión, los tamaños de dimensión de las entradas son iguales o uno de ellos es 1. Consulte Tamaños de matriz compatibles para operaciones básicas y Operaciones de matriz frente a matriz para obtener más información.
Element-wise arithmetic operators — +, -, .*, .^, ./, .\ Relational operators — <, <=, >, >=, ==, ~= Logical operators — &, |, xor Bit-wise functions — bitand, bitor, bitxor Elementary math functions — max, min, mod, rem, hypot, atan2, atan2d
Por ejemplo, puede calcular la media de cada columna en una matriz A y luego restar el vector de valores medios de cada columna con A - media (A).
Anteriormente, esta funcionalidad estaba disponible a través de la función bsxfun. Ahora se recomienda que reemplace la mayoría de los usos de bsxfun con llamadas directas a las funciones y operadores que admiten la expansión implícita. En comparación con el uso de bsxfun, la expansión implícita ofrece una velocidad más rápida, un mejor uso de la memoria y una mejor legibilidad del código.
Ninguna de las respuestas anteriores funcionó "fuera de la caja" para mí, sin embargo, la siguiente función, obtenida al copiar las ideas de las otras respuestas, funciona:
apply_func_2_cols = @(f,M) cell2mat(cellfun(f,num2cell(M,1), 'UniformOutput',0));
Toma una función f
y la aplica a cada columna de la matriz M
.
Así por ejemplo:
f = @(v) [0 1;1 0]*v + [0 0.1]';
apply_func_2_cols(f,[0 0 1 1;0 1 0 1])
ans =
0.00000 1.00000 0.00000 1.00000
0.10000 0.10000 1.10000 1.10000
Con las versiones recientes de Matlab, puede utilizar la estructura de datos de la tabla a su favor. Incluso hay una operación 'rowfun', pero me resultó más fácil hacer esto:
a = magic(6);
incrementRow = cell2mat(cellfun(@(x) x+1,table2cell(table(a)),'UniformOutput',0))
o aquí hay uno más antiguo que tenía que no requiere tablas, para versiones anteriores de Matlab.
dataBinner = cell2mat(arrayfun(@(x) Binner(a(x,:),2)',1:size(a,1),'UniformOutput',0)')
La respuesta aceptada parece ser convertir primero a celdas y luego usar cellfun
para operar sobre todas las celdas. No conozco la aplicación específica, pero en general creo que usar bsxfun
para operar sobre la matriz sería más eficiente. Básicamente, bsxfun
aplica una operación elemento por elemento en dos matrices. Entonces, si quisiera multiplicar cada elemento en un n x 1
vector por cada elemento en un m x 1
vector para obtener una n x m
matriz, podría usar:
vec1 = [ stuff ]; % n x 1 vector
vec2 = [ stuff ]; % m x 1 vector
result = bsxfun('times', vec1.', vec2);
Esto le dará una matriz llamada result
en la que la entrada (i, j) será el i-ésimo elemento de vec1
multiplicado por el j-ésimo elemento de vec2
.
Puede utilizarlo bsxfun
para todo tipo de funciones integradas y puede declarar las suyas propias. La documentación tiene una lista de muchas funciones integradas, pero básicamente puede nombrar cualquier función que acepte dos matrices (vector o matriz) como argumentos y hacer que funcione.
Me encontré con esta pregunta / respuesta mientras buscaba cómo calcular las sumas de fila de una matriz.
Solo me gustaría agregar que la función SUMA de Matlab en realidad tiene soporte para sumar para una dimensión determinada, es decir, una matriz estándar con dos dimensiones.
Entonces, para calcular las sumas de las columnas, haga lo siguiente:
colsum = sum(M) % or sum(M, 1)
y para las sumas de fila, simplemente haz
rowsum = sum(M, 2)
Mi apuesta es que esto es más rápido que programar un bucle for y convertir a celdas :)
Todo esto se puede encontrar en la ayuda de matlab para SUM.
si conoce la longitud de sus filas, puede hacer algo como esto:
a=rand(9,3);
b=rand(9,3);
arrayfun(@(x1,x2,y1,y2,z1,z2) line([x1,x2],[y1,y2],[z1,z2]) , a(:,1),b(:,1),a(:,2),b(:,2),a(:,3),b(:,3) )