Question

Je souhaite appliquer une fonction à toutes les colonnes d'une matrice avec MATLAB. Par exemple, j'aimerais pouvoir appeler smooth sur chaque colonne d'une matrice, au lieu de le traiter en tant que vecteur (ce qui est le comportement par défaut si vous appelez smooth (matrix) ).

Je suis sûr qu'il doit exister un moyen plus idiomatique de le faire, mais je ne le trouve pas. J'ai donc défini une fonction map_column :

function result = map_column(m, func)
    result = m;
    for col = 1:size(m,2)
        result(:,col) = func(m(:,col));
    end
end

avec lequel je peux appeler:

smoothed = map_column(input, @(c) (smooth(c, 9)));

Quelque chose ne va pas avec ce code? Comment pourrais-je l'améliorer?

Était-ce utile?

La solution

Votre solution est satisfaisante.

Notez que horizcat impose une perte de performance substantielle pour les grandes matrices. Cela fait que le code soit O (N ^ 2) au lieu de O (N). Pour une matrice de 100 x 10 000, votre implémentation prend 2.6 s sur ma machine, celle d’horizon 64,5 s. Pour une matrice 100x5000, la mise en œuvre d’horizoncat prend 15,7 secondes.

Si vous le souhaitez, vous pouvez généraliser un peu votre fonction et lui permettre de parcourir la dernière dimension, voire même des dimensions arbitraires (pas uniquement des colonnes).

Autres conseils

Le MATLAB " pour " En fait, l'instruction boucle sur les colonnes de tout ce qui est fourni - normalement, il en résulte simplement une séquence de scalaires puisque le vecteur passé dans (comme dans l'exemple ci-dessus) est un vecteur ligne. Cela signifie que vous pouvez réécrire le code ci-dessus comme ceci:

function result = map_column(m, func)
    result = [];
    for m_col = m
      result = horzcat(result, func(m_col));
    end

Si func ne renvoie pas de vecteur de colonne, vous pouvez ajouter quelque chose comme

f = func(m_col);
result = horzcat(result, f(:));

pour le forcer dans une colonne.

Peut-être pourriez-vous toujours transformer la matrice avec l'opérateur ', puis transformer le résultat en retour.

smoothed = smooth(input', 9)';

Cela fonctionne au moins avec la fonction fft.

Une méthode pour provoquer une boucle implicite sur les colonnes d'une matrice consiste à utiliser cellfun. C'est-à-dire que vous devez d'abord convertir la matrice en tableau de cellules, chaque cellule contiendra une colonne. Ensuite, appelez cellfun. Par exemple:

A = randn(10,5);

Vous voyez ici que j'ai calculé l'écart type pour chaque colonne.

cellfun(@std,mat2cell(A,size(A,1),ones(1,size(A,2))))

ans =
      0.78681       1.1473      0.89789      0.66635       1.3482

Bien entendu, de nombreuses fonctions de MATLAB sont déjà configurées pour fonctionner sur les lignes ou les colonnes d’un tableau, comme l’indique l’utilisateur. Ceci est vrai pour std bien sûr, mais c'est un moyen pratique de tester que cellfun a fonctionné avec succès.

std(A,[],1)

ans =
      0.78681       1.1473      0.89789      0.66635       1.3482

N'oubliez pas de préallouer la matrice de résultats si vous utilisez de grandes matrices. Sinon, votre CPU passera de nombreux cycles à réaffecter la matrice à chaque fois qu'il ajoute une nouvelle ligne / colonne.

S'il s'agit d'un cas d'utilisation courant pour votre fonction, ce serait peut-être une bonne idée de la faire parcourir automatiquement par les colonnes si l'entrée n'est pas un vecteur.

Cela ne résoudra pas votre problème, mais simplifierait l'utilisation des fonctions. Dans ce cas, le résultat devrait également être une matrice.

Vous pouvez également transformer la matrice en une colonne longue en utilisant m (:, :) = m (:) . Toutefois, cela dépend de votre fonction si cela vous semble logique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top