Question

Vous pouvez appliquer une fonction à chaque élément dans un vecteur en disant, par exemple, v + 1, ou vous pouvez utiliser la fonction arrayfun. Comment puis-je faire pour chaque ligne / colonne d'une matrice sans utiliser une boucle for?

Était-ce utile?

La solution

De nombreuses opérations intégrées comme sum et prod sont déjà en mesure de fonctionner à travers des lignes ou des colonnes, de sorte que vous pourrez peut-être factoriser la la fonction que vous postulez pour tirer profit de cela.

Si ce n'est pas une option viable, une façon de le faire est de collecter les lignes ou les colonnes dans des cellules en utilisant mat2cell ou href="http://www.mathworks.com/help/matlab/ref/num2cell.html" rel="noreferrer"> num2cell , puis utiliser cellfun pour fonctionner sur le réseau de cellules résultante.

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

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

Et voici comment vous le faire en utilisant le plus compliqué 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

Autres conseils

Vous pouvez plus obscure fonction Matlab bsxfun . De la documentation Matlab, bsxfun « applique l'opération binaire élément par élément spécifié par l'amusement de la poignée de fonction aux tableaux A et B, avec extension singleton activé. »

@gnovice indiqué ci-dessus cette somme et d'autres fonctions de base fonctionne déjà sur la première dimension non-singleton (par exemple, des lignes, s'il y a plus d'une rangée, les colonnes s'il n'y a qu'une seule ligne, ou des dimensions supérieures si les dimensions inférieures ont toutes la taille == 1). Cependant, bsxfun fonctionne pour toutes les fonctions, y compris (et surtout) des fonctions définies par l'utilisateur.

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

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

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

A partir de 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]

i.e..

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

Vous pouvez le faire de la façon de la force brute à l'aide repmat:

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

Ou vous pouvez faire le chemin classe en utilisant bsxfun, qui prend en charge en interne l'étape de repmat:

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

bsxfun vous permet d'économiser quelques étapes (vous n'avez pas besoin de calculer explicitement les dimensions de A). Cependant, dans certains tests informels de moi, il se trouve que repmat est à peu près deux fois plus vite si la fonction à appliquer (comme ma fonction de puissance, ci-dessus) est simple. Donc, vous devrez choisir si vous voulez la simplicité ou la vitesse.

Je ne peux pas commenter sur la façon dont cela est efficace, 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)

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

Pour être complet / intérêt que je voudrais ajouter que Matlab a une fonction qui vous permet d'utiliser des données par ligne plutôt que par élément. Il est appelé rowfun ( http://www.mathworks.se/help/matlab/ ref / rowfun.html ), mais le seul "problème" est qu'il fonctionne sur des tables ( http://www.mathworks.se/help/matlab/ref/table.html ) plutôt que matrices .

Ajout de la nature évolutive de la réponse à cette question, en commençant par r2016b, Matlab élargira implicitement les dimensions singleton, supprimant la nécessité d'bsxfun dans de nombreux cas.

De la de r2016b note :

  

extension implicite: appliquer des opérations et des fonctions-élément par élément à dilatation automatique des tableaux avec des dimensions de longueur 1

     

extension implicite est une généralisation de l'expansion scalaire. Avec   l'expansion scalaire, un scalaire se dilate pour avoir la même taille que l'autre   matrice pour faciliter les opérations élément par élément. Avec l'expansion implicite,   les opérateurs et les fonctions élément par élément énumérés ici peuvent implicitement   élargir leurs entrées à la même taille, tant que les tableaux ont   tailles compatibles. Deux tableaux ont des tailles compatibles si, pour chaque   dimension, la taille de la dimension des entrées sont identiques ou   l'un d'eux est 1. Voir tableau compatible avec les tailles pour les opérations de base et   Tableau des opérations par rapport à la matrice pour plus d'informations.

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
     

Par exemple, vous pouvez calculer la moyenne de chaque colonne dans une matrice A,   et soustraire le vecteur de valeurs moyennes de chaque colonne avec A -   moyenne (A).

     

Auparavant, cette fonctionnalité est disponible via la fonction bsxfun.   Il est maintenant recommandé de remplacer la plupart des utilisations de bsxfun avec directe   appels aux fonctions et aux opérateurs qui prennent en charge l'expansion implicite.   Par rapport à l'utilisation bsxfun, l'expansion implicite offre une plus grande vitesse,   une meilleure utilisation de la mémoire, et une meilleure lisibilité du code.

Avec les versions récentes de Matlab, vous pouvez utiliser la structure de données de table à votre avantage. Il y a même une opération « rowfun », mais je l'ai trouvé plus facile de faire ceci:

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

ou est ici une version plus ancienne que j'avais qui ne nécessite pas de tables, pour les anciennes versions de Matlab.

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

Aucune des réponses ci-dessus a travaillé « de la boîte » pour moi, cependant, la fonction suivante, obtenue en copiant les idées des autres réponses fonctionne:

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

Il faut une fonction f et l'applique à toutes les colonnes de la matrice M.

Ainsi, par exemple:

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

La réponse acceptée semble être de convertir les cellules d'abord et ensuite utiliser cellfun pour fonctionner sur toutes les cellules. Je ne sais pas l'application spécifique, mais en général, je pense en utilisant bsxfun pour fonctionner sur la matrice serait plus efficace. Fondamentalement bsxfun applique un élément par élément opération à travers deux réseaux. Donc, si vous vouliez multiplier chaque élément dans un vecteur de n x 1 par chaque élément dans un vecteur de m x 1 pour obtenir un tableau de n x m, vous pouvez utiliser:

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

Cela vous donnera matrice appelée result dans lequel le (i, j) l'entrée sera le ième élément de vec1 multiplié par l'élément j du vec2.

Vous pouvez utiliser bsxfun pour toutes sortes de fonctions intégrées, et vous pouvez déclarer votre propre. La documentation a une liste de nombreuses fonctions intégrées, mais vous pouvez nommer essentiellement une fonction qui accepte deux tableaux (vecteur ou matrice) comme arguments et le faire fonctionner.

Nous sommes tombés sur cette question / réponse tout en cherchant comment calculer les sommes des lignes d'une matrice.

Je voudrais juste ajouter que la fonction SOMME de Matlab a fait un soutien pour faire la somme pour une dimension donnée, i.e. une matrice standard avec deux dimensions.

Donc, pour calculer les sommes des colonnes font:

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

et pour les sommes de ligne, il suffit de faire

rowsum = sum(M, 2)

Mon pari est que c'est plus rapide que la fois une programmation pour la boucle et la conversion des cellules:)

Tout cela se trouve dans l'aide Matlab pour SUM.

si vous connaissez la longueur de vos lignes que vous pouvez faire quelque chose comme ceci:

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) )
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top