Je travaille avec Matlab.
J'ai une matrice carrée binaire. Pour chaque ligne, il y a une ou plusieurs entrées de 1. Je veux parcourir chaque ligne de cette matrice et retourner l'index de ces 1 et les stocker dans l'entrée d'une cellule.
Je me demandais s'il y avait un moyen de le faire sans boucler sur toutes les lignes de cette matrice, car la boucle est vraiment lente dans Matlab.
Par exemple, ma matrice
M = 0 1 0
1 0 1
1 1 1
Finalement, je veux quelque chose comme
A = [2]
[1,3]
[1,2,3]
Il en A
va de même pour une cellule.
Existe-t-il un moyen d'atteindre cet objectif sans utiliser de boucle for, dans le but de calculer le résultat plus rapidement?
matlab
vectorization
ftxx
la source
la source
for
boucles? Pour ce problème, avec les versions modernes de MATLAB, je soupçonne fortement qu'unefor
boucle est la solution la plus rapide. Si vous avez un problème de performances, je soupçonne que vous cherchez au mauvais endroit la solution basée sur des conseils obsolètes.cellfun
.1
s dans une rangée typique? Je ne m'attendrais pas à ce qu'unefind
boucle prenne quelque chose près de 30 secondes pour quelque chose d'assez petit pour tenir sur la mémoire physique.Réponses:
Au bas de cette réponse se trouve un code de référence, car vous avez précisé que vous êtes intéressé par les performances plutôt que d'éviter arbitrairement les
for
boucles.En fait, je pense que les
for
boucles sont probablement l'option la plus performante ici. Depuis que le "nouveau" moteur JIT (2015b) a été introduit ( source ), lesfor
boucles ne sont pas intrinsèquement lentes - en fait, elles sont optimisées en interne.Vous pouvez voir dans le benchmark que l'
mat2cell
option offerte par ThomasIsCoding ici est très lente ...Si nous nous débarrassons de cette ligne pour rendre l'échelle plus claire, alors ma
splitapply
méthode est assez lente, l' option accumarray d' Obchardon est un peu meilleure, mais les options les plus rapides (et comparables) utilisent soitarrayfun
(comme l'a également suggéré Thomas) soit unefor
boucle. Notez quearrayfun
c'est essentiellement unefor
boucle déguisée pour la plupart des cas d'utilisation, donc ce n'est pas une cravate surprenante!Je vous recommande d'utiliser unefor
boucle pour une meilleure lisibilité du code et les meilleures performances.Modifier :
Si nous supposons que le bouclage est l'approche la plus rapide, nous pouvons faire quelques optimisations autour de la
find
commande.Plus précisément
Rendez
M
logique. Comme le montre le graphique ci-dessous, cela peut être plus rapide pour les relativement petitsM
, mais plus lent avec le compromis de conversion de type pour les grandsM
.Utilisez une logique
M
pour indexer un tableau1:size(M,2)
au lieu d'utiliserfind
. Cela évite la partie la plus lente de la boucle (lafind
commande) et l'emporte sur la surcharge de conversion de type, ce qui en fait l'option la plus rapide.Voici ma recommandation pour de meilleures performances:
Je l'ai ajouté au benchmark ci-dessous, voici la comparaison des approches de style boucle:
Code de référence:
la source
M
. Si, par exemple, seulement 5% des éléments sont remplis,M = randi([0,20],N) == 20;
lafor
boucle est de loin la plus lente et votrearrayfun
méthode gagne.accumarray
sansind2sub
, mais elle est plus lente que lafor
boucleVous pouvez essayer
arrayfun
comme ci-dessous, qui parcourent des rangées deM
ou (une approche plus lente de
mat2cell
)la source
arrayfun
essentiellement d'un déguisement en boucle, cela peut échouer sur les deux fronts: 1) éviter les boucles et 2) être rapide, comme l'espérait l'OPEdit : j'ai ajouté un benchmark, les résultats montrent qu'une boucle for est plus efficace que
accumarray
.Vous pouvez utiliser
find
etaccumarray
:La matrice est transposée (
A'
) carfind
regroupée par colonne.Exemple:
Production:
Référence:
Résultat:
Une boucle for est plus efficace que
accumarray
...la source
Utilisation de cumularray :
la source
MM{I} = find(M(I, :))
.ind2sub
:[ii, jj] = find(M); accumarray(ii, jj, [], @(x){x})
Vous pouvez utiliser strfind :
la source
string
types réels plutôt que des caractères? Il y a beaucoup d'optimisations pour les chaînes, d'où leur existence ...