2010-02-21 17 views

Respuesta

66

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 eso no es una opción viable, una forma de hacerlo es recoger las filas o columnas en las células usando mat2cell o num2cell, a continuación, utilizar cellfun para operar en la matriz celular resultante.

Como ejemplo, supongamos que desea sumar las columnas de una matriz M. Usted puede hacer esto simplemente utilizando sum:

M = magic(10);   %# A 10-by-10 matrix 
columnSums = sum(M, 1); %# A 1-by-10 vector of sums for each column 

Y aquí es cómo se podría hacer esto utilizando la más complicada num2cell/cellfun opción:

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 
+16

I habría probar el rendimiento de este enfoque para cualquier caso particular contra simple para-loop, que podría ser más rápido que la conversión de una matriz a la célula de agrupación. Use tic/tac wrap para probar. – yuk

+5

@yuk: Creo que quisiste decir "tic/toc". ;) – gnovice

+2

Vaya, por supuesto! Solo algo marca ... :) – yuk

-1

Tropezamos con esta pregunta/respuesta mientras se busca la manera de calcular las sumas de fila de una matriz.

Me gustaría agregar que la función SUM de Matlab en realidad tiene soporte para sumar para una dimensión dada, es decir, una matriz estándar con dos dimensiones.

Así que para calcular las sumas de las columnas hacen:

colsum = sum(M) % or sum(M, 1) 

y por las sumas de filas, sólo tiene que hacer

rowsum = sum(M, 2) 

Mi apuesta es que esto es más rápido que tanto la programación de un bucle y la conversión a celdas :)

Todo esto se puede encontrar en la ayuda de matlab para SUM.

+7

la capacidad de aplicar SUM a lo largo de una dimensión dada se mencionó en la primera oración de la respuesta original a esta pregunta. La respuesta pasó a abordar el caso cuando la capacidad de elegir una dimensión no está incorporada a la función. Sin embargo, tiene razón en que el uso de las opciones de selección de dimensión incorporadas, cuando están disponibles, casi siempre es más rápido que un bucle for o la conversión a celdas. – cjh

+0

Es cierto que, sin embargo, la respuesta anterior me envió de vuelta a la documentación de matlab, ya que no necesitaba toda esa sofisticación, por lo que solo quería compartir y salvar a otros, necesitados de la solución simple, de la búsqueda. – nover

18

que no puedo comentar sobre la efectividad de este es, pero aquí es 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) 
+0

Se da una respuesta más genérica [aquí] (http://stackoverflow.com/a/15971182/376454). – Wok

9

Basándose en Alex's answer, aquí es 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í está 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))' 
22

Es posible que desee la función Matlab más oscura bsxfun. 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 indica que la suma y otras funciones básicas ya operan en la primera dimensión no única (es decir, filas si hay más de una fila, columnas si solo hay una fila o dimensiones superiores si todas las dimensiones inferiores tienen tamaño == 1). Sin embargo, bsxfun funciona para cualquier función, incluidas (y especialmente) funciones definidas por el usuario.

Por ejemplo, digamos que usted 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 power_by_col función que devuelve en un vector C todos los elementos de A a la potencia de la columna correspondiente de B.

en el ejemplo anterior, C es una matriz 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] 

Usted puede hacer esto al bruto manera la fuerza utilizando repmat:

C = A.^repmat(B, size(A, 1), 1) 

O usted podría hacer esto de la manera elegante usando bsxfun, que lleva internamente el cuidado 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.

0

La respuesta aceptada parece ser primero convertir 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. Así que si quería multiplicar cada elemento en un vector de n x 1 por cada elemento en un vector de m x 1 para obtener una matriz n x m, se puede utilizar:

vec1 = [ stuff ]; % n x 1 vector 
vec2 = [ stuff ]; $ m x 1 vector 
result = bsxfun('times', vec1.', vec2); 

Esto le dará la matriz de llamada result en el que (i, j) la entrada será el elemento ith de vec1 multiplicado por el elemento j-ésimo de vec2.

Puede usar bsxfun para todo tipo de funciones incorporadas, y puede declarar las suyas propias. La documentación tiene una lista de muchas funciones incorporadas, pero básicamente puede nombrar cualquier función que acepte dos matrices (vector o matriz) como argumentos y hacer que funcione.

-1

si conoce la longitud de sus filas que 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)) 
+1

Para cualquiera que vea esta respuesta: ¡Esta no es la manera de hacerlo! ¡Esta no es la manera de hacer nada en MATLAB! –

1

Con las versiones recientes de Matlab, puede utilizar la estructura de datos de tabla para su ventaja.Incluso hay una operación de 'rowfun', pero me pareció más fácil simplemente hacer esto:

a = magic(6); 
incrementRow = cell2mat(cellfun(@(x) x+1,table2cell(table(a)),'UniformOutput',0)) 

o aquí es una más antigua que tenía que no requiere tablas, para versiones de Matlab.

dataBinner = cell2mat(arrayfun(@(x) Binner(a(x,:),2)',1:size(a,1),'UniformOutput',0)') 
3

Agregando a la naturaleza cambiante de la respuesta a esta pregunta, a partir de r2016b, MATLAB implícitamente ampliar las dimensiones Singleton, eliminando la necesidad de bsxfun en muchos casos.

Desde el r2016b release notes:

expansión implícita: Aplicar operaciones y funciones de los elementos en cuanto a las matrices con la expansión automática de dimensiones de longitud 1

expansión implícita es una generalización de 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 elemento. Con la expansión implícita, , los operadores y las funciones de elementos enumerados aquí implícitamente pueden expandir 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 las entradas son los mismos 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, se puede calcular la media de cada columna de una matriz A, y luego restar el vector de los 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 expansión implícita. En comparación con el uso de bsxfun, la expansión implícita ofrece una velocidad más rápida, mejor uso de la memoria y una mejor legibilidad del código.

0

Ninguna de las respuestas anteriores dio resultado "fuera de la caja" para mí, sin embargo, la siguiente función, que se obtiene copiando las ideas de las otras respuestas funciona:

apply_func_2_cols = @(f,M) cell2mat(cellfun(f,num2cell(M,1), 'UniformOutput',0)); 

Se toma una función f y lo 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 
Cuestiones relacionadas