8
votes

Moyen le plus rapide de trouver des valeurs uniques dans un tableau

J'essaie de trouver un moyen le plus rapide de trouver des valeurs uniques dans une matrice et de supprimer 0 code> comme une possibilité de valeur unique.

À l'heure actuelle, j'ai deux solutions: P > xxx pré>

dataarray code> est équivalent à: p> xxx pré>

donc dans ce cas, résultat1 code> est égal à [1; 2] code> et résultat2 code> est égal à [0; 1; 2] code>. La fonction code> unique > est plus rapide mais je ne veux pas 0 code> à envisager. Existe-t-il un moyen de le faire avec unique code> et ne pas envisager 0 code> comme valeur unique? Y a-t-il une autre alternative? P>

EDIT STRORT> P>

Je voulais faire du temps les différentes solutions. P>

Elapsed time is 5.153571 seconds. % FCT1 Initial
Elapsed time is 3.837637 seconds. % FCT2 My solution
Elapsed time is 3.464652 seconds. % FCT3 Pursuit solution
Elapsed time is 3.414338 seconds. % FCT32 Pursuit solution with chappjc comment
Elapsed time is 4.097164 seconds. % FCT4 chappjc solution
Elapsed time is 0.936623 seconds. % FCT5 chappjc 2nd solution


8 commentaires

@CHAPPJC Vous avez raison, le 'lignes' n'est pas nécessaire. Je l'ai supprimé.


Vous voudrez peut-être essayer les horaires plus longs dataarray plutôt que plus d'itérations. Mais juste pour des coups de pied, lancez-le dans fct3 = fct3 (fct3 ~ = 0); car cela est généralement plus rapide que d'attribuer [] ;


D'accord avec @CHAPPJC - Votre timing est dominé par une ou deux appels de fonction. Essayez ceci sur un "gros" tableau (voir ma réponse pour un exemple). Vous avez surtout chronométrant la surcharge de boucle (et d'appel de fonction) avec votre code actuel, plutôt que de l'efficacité des fonctions une fois que vous êtes à l'intérieur d'eux.


@chappjc 2nd Solution semble être le plus rapide, pour l'instant: ré.


@M_Power examine les réponses de Floris, ainsi que ses commandes de données de test qui retirent certains éléments pour un test plus robuste. Si vous le souhaitez, vous pouvez également faire toutes les 10 colonnes d'un coup avec rand (10E3,10) .


@chappjc j'ai fait les modifications. Il n'y a pas de modification des résultats finaux.


@m_Power comme je l'ai mentionné dans mes commentaires ci-dessous, il y a des défis avec des numéros de points flottants même avec unique . Voir ici et ici . Considérez si vous pouvez utiliser avec des index valorisés intégrés plutôt que sur des valeurs de points flottantes.


@chappjc Inspiré par votre dernier commentaire J'ai mis à jour ma réponse une fois de plus ...


4 Réponses :


3
votes

Pourquoi ne pas retirer les zéros comme une deuxième étape: xxx


1 commentaires

résultat2 = résultat2 (résultat2 ~ = 0) peut être plus rapide: Stackoverflow.com/questions/12421345/...



5
votes

Voici une suggestion farfelée avec accumarray , démontré à l'aide de données de test de floris: xxx

grâce à Luis Mendo pour souligner que avec nonzeros , il n'est pas nécessaire d'exécuter résultat = résultat (résultat> 0) !

Notez que cette solution nécessite des données valorisées (pas nécessairement un type de données entier, mais juste pas avec des composants décimaux). La comparaison des valeurs de points flottants pour l'égalité, comme le ferait des valeurs uniques, est périlleux. Voir ici et ICI .


Suggestion originale: Combinez unique avec SetDiff : xxx

ou supprimez avec indexation logique après unique : xxx

Je préfère généralement ne pas attribuer [] comme dans ( résultat (résultat == 0) = []; ) car il devient très inefficace pour les grands ensembles de données.

Suppression de zéros après Unique devrait être plus rapide car celui-ci fonctionne moins de données (sauf si chaque élément est unique, ou si a dataarray > est très court).


8 commentaires

Lorsque vous utilisez A 10000x10, j'obtiens l'erreur suivante: ??? Erreur lors de l'utilisation de ==> Accumparray Taille variable maximale autorisée par le programme est dépassée.


@M_Power doit utiliser uniquement la première colonne ( A (:, 1) ) comme les autres solutions. Mis à jour.


Wacky, peut-être. Mais rapide!


Et s'il existe double dans le tableau ? Je reçois l'erreur Les premiers sous-traitants doivent contenir des sous-domestibles entier positif. .


@M_Power Droite, cela et le Sans Solutions ne fonctionnent que pour des données valorisées entier, mais vous ne souhaitez généralement pas comparer les valeurs de point flottantes pour l'égalité (comme avec unique aussi ). Je devrais dire que vous vraiment ne devrait pas.


@chappjc Le fait est qu'il existe double dans mon tableau, je n'ai pas pensé que cela causerait un problème dans mon exemple initial.


@M_Power je reconsidérerais le problème en fonction des valeurs attendues. Sont-ils continus ou seront-ils certaines valeurs? Il y a Problèmes utilisant un unique sur le double bien que cela vous permettrait de l'exécuter . Il faut se méfier.


@chappjc +1, mais pourquoi ne pas supprimer les éléments zéro avant accumarray ?: résultat = Rechercher (ACCUMARRAY (NONZEROS (A (:: 1)) + 1 , 1) -1); . Il faut moins de temps sur mon ordinateur.



0
votes

J'ai aussi trouvé une autre façon de le faire:

result2 = unique(dataArray(dataArray(:,1)>0,1));


2 commentaires

Juste un conseil: 1: fin est identique à celui de : . Mais oui, c'est une solution réalisable.


Strictement parler que vous devriez utiliser dataarray (:, 1) ~ = 0 pour permettre la possibilité de nombres négatifs. Je soupçonne que c'est plus rapide de retirer le zéro supplémentaire à la fin (réseau plus petit pour manipuler).



5
votes

Juste pour ajouter à la clameur générale - voici trois méthodes différentes. Ils donnent tous la même réponse, mais des horaires légèrement différents: xxx pré>

sur ma machine, les horaires (pour une matrice de 100 000 éléments) étaient les suivants: P>

a = round(a * 1000);
mina = min(a(:));
b = find(accumarray(a - mina + 1, 1)) + mina - 1;
b = 0.001 * b(b ~= 0);


6 commentaires

Je préfère accumarray à SPARSE . Tu veux ajouter les horaires. ;)


@chappjc c'était une suggestion formidable. Il est 3 fois plus rapide (sur ma machine)!


Merci, merci. Mais ce n'est probablement qu'une question de temps jusqu'à ce qu'un plus rapide vienne. ;)


Votre troisième solution fonctionne correctement, mais je ne peux pas l'utiliser pour ce que je fais. J'ai besoin d'avoir les mêmes valeurs exactes, pas des valeurs arrondies.


@M_Power Pourriez-vous publier des données réelles sur Dropbox ou quelque part similaire. Je suis sceptique que vous obtiendrez une solution satisfaisante avec tout ce qui n'utilise pas de tolérances, y compris unique . Tester des valeurs de points flottants pour l'égalité fonctionne rarement comme souhaité.


@Floris Comme je viens de commenter la réponse de Chappjc: pourquoi ne pas supprimer les éléments zéro initialement ? Dans la version Accumarray , qui semble sauvegarder un peu de temps (sur ma machine): b5 = trouver (Accumarray (nonzeros (A (:, 1)) + 1,1) -1 )