103 votes

comment appliquer une fonction à chaque ligne en matlab ?

Vous pouvez appliquer une fonction à chaque élément d'un vecteur en disant v .+ 1, ou vous pouvez utiliser arrayfun, quelqu'un a une suggestion sur la façon de le faire pour chaque ligne/colonne d'une matrice sans utiliser la boucle for ?

69voto

gnovice Points 70970

De nombreuses opérations intégrées comme SOMME et PROD sont déjà capables d'opérer sur des lignes ou des colonnes, vous pouvez donc remanier la fonction que vous appliquez pour en tirer parti.

Si ce n'est pas une option viable, une façon de procéder consiste à rassembler les lignes ou les colonnes dans des cellules à l'aide de la fonction MAT2CELL ou NUM2CELL puis utiliser CELLFUN pour opérer sur le tableau de cellules résultant.

À titre d'exemple, disons que vous voulez additionner les colonnes d'une matrice M . Vous pouvez le faire en utilisant simplement SOMME :

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

Et voici comment vous feriez en utilisant la méthode plus compliquée NUM2CELL / CELLFUN option :

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

24voto

Daniel Golden Points 589

Vous pouvez vouloir la fonction Matlab plus obscure bsxfun . D'après la documentation de Matlab, bsxfun "applique l'opération binaire élément par élément spécifiée par la poignée de fonction fun aux tableaux A et B, avec l'expansion singleton activée".

@gnovice a indiqué plus haut que la somme et d'autres fonctions de base opèrent déjà sur la première dimension non singleton (c'est-à-dire les lignes s'il y a plus d'une ligne, les colonnes s'il n'y a qu'une ligne, ou les dimensions supérieures si les dimensions inférieures ont toutes une taille==1). Cependant, bsxfun fonctionne pour toute fonction, y compris (et surtout) les fonctions définies par l'utilisateur.

Par exemple, disons que vous avez une matrice A et un vecteur de ligne B. Par exemple, disons :

A = [1 2 3;
     4 5 6;
     7 8 9]
B = [0 1 2]

Vous voulez une fonction puissance_par_col qui retourne dans un vecteur C tous les éléments de A à la puissance de la colonne correspondante de B.

Dans l'exemple ci-dessus, C est une matrice 3x3 :

C = [1^0 2^1 3^2;
     4^0 5^1 6^2;
     7^0 8^1 9^2]

c'est-à-dire,

C = [1 2 9;
     1 5 36;
     1 8 81]

Vous pouvez le faire par la force brute en utilisant repmat :

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

Ou vous pouvez le faire de manière classique en utilisant bsxfun, qui s'occupe en interne de l'étape repmat :

C = bsxfun(@(x,y) x.^y, A, B)

Ainsi, bsxfun vous fait gagner quelques étapes (vous n'avez pas besoin de calculer explicitement les dimensions de A). Cependant, lors de certains de mes tests informels, il s'est avéré que repmat est environ deux fois plus rapide si la fonction à appliquer (comme ma fonction puissance, ci-dessus) est simple. Vous devrez donc choisir si vous voulez la simplicité ou la rapidité.

19voto

Alex Points 101

Je ne peux pas me prononcer sur l'efficacité de cette méthode, mais voici une solution :

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)

11voto

Wok Points 2020

Construire sur Réponse d'Alex voici une fonction plus générique :

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));

Voici une comparaison entre les deux fonctions :

>> % 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))'

6voto

kamjagin Points 1598

Pour compléter/intéresser, je voudrais ajouter que Matlab a une fonction qui vous permet d'opérer sur des données par ligne plutôt que par élément. Elle s'appelle rowfun ( http://www.mathworks.se/help/matlab/ref/rowfun.html ), mais le seul "problème" est qu'elle fonctionne sur tableaux ( http://www.mathworks.se/help/matlab/ref/table.html ) plutôt que matrices .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X