2011-03-11 3 views
1

je le défi suivant dans une simulation pour ma thèse de doctorat:opérations mathématiques efficaces sur les parties de tableaux de numpy « rares »

Je dois optimiser le code suivant:

repelling_forces = repelling_force_prefactor * np.exp(-(height_r_t/potential_steepness)) 

Dans cet extrait de code 'height_r_t' est un vrai tableau Numpy et 'potential_steepness' est un scalaire. 'repelling_force_prefactor' est également un tableau Numpy, qui est la plupart du temps ZERO, mais ONE à une position pré-calculée, qui ne change pas pendant l'exécution (c'est-à-dire un masque). De toute évidence, le code est inefficace car il serait beaucoup plus logique de ne calculer que la fonction exponentielle aux positions, où 'repelling_force_prefactor' est différent de zéro. La question est de savoir comment je fais cela de la manière la plus efficace? La seule idée que j'ai jusqu'à maintenant serait de définir la tranche à 'height_r_t' en utilisant 'repelling_force_prefactor' et d'appliquer 'np.exp' à ces tranches. Cependant, j'ai fait l'expérience que le découpage est lent (je ne sais pas si c'est généralement correct) et la solution semble maladroite. Juste comme une note de côté le ration de 1 à 0 dans 'repelling_force_prefactor' est d'environ 1/1000 et je cours cela en boucle, donc l'efficacité est très importante. (Commentaire: Je n'aurais pas de problème avec Cython, car j'aurai besoin de l'apprendre à un moment donné ... mais je suis novice, donc j'ai besoin d'un bon pointeur/explication.)

Répondre

3

Les tableaux masqués sont implémentés exactement pour vos besoins.

Performance est le même que la réponse de Sven:

height_r_t = np.ma.masked_where(repelling_force_prefactor == 0, height_r_t) 
repelling_forces = np.ma.exp(-(height_r_t/potential_steepness)) 

l'avantage des tableaux masqués est que vous n'avez pas à couper et élargir votre gamme, la taille est toujours le même, mais numpy sait automatiquement pas calculer l'exp où le tableau est masqué.

Vous pouvez également additionner un tableau avec différents masques et le tableau résultant a l'intersection des masques.

+0

C'est une très belle, parce que la solution élégante. Une autre question - vous en avez peut-être parlé dans votre dernière phrase. Pourrais-je utiliser cette méthode pour effectuer des opérations sur différentes parties de la matrice? c'est à dire.comme ceci: height_part1 = hauteur (masque1) height_part2 = hauteur (mask2) – packoman

+0

Et puis si je fais des opérations mathématiques sur height_part1 ou height_part2, comme height_part1 = exploitation1 (height_part1), seront-ils pris en compte dans la hauteur? – packoman

+0

oui, le masque est un simple tableau booléen stocké dans l'attribut '.mask' du masked_array. Lorsque vous créez un tableau masqué, vous pouvez spécifier copy = False pour que vos opérations soient reflétées dans le tableau d'origine. mais la meilleure stratégie dépend des détails de votre application. –

2

Le découpage est probablement beaucoup plus rapide que le calcul de toutes les exponentielles. Au lieu d'utiliser le masque repelling_force_prefactor pour trancher directement, je vous suggère de précalculer les indices où il est non nul et les utiliser pour trancher:

# before the loop 
indices = np.nonzero(repelling_force_prefactor) 

# inside the loop 
repelling_forces = np.exp(-(height_r_t[indices]/potential_steepness)) 

Maintenant repelling_forces ne contiendra que les résultats ne sont pas nuls. Si vous devez mettre à jour un tableau de la forme d'origine de height_r_t avec ces valeurs, vous pouvez utiliser à nouveau le découpage avec indices ou utiliser np.put() ou une fonction similaire.

Le découpage avec la liste des indices sera plus efficace que le découpage en tranches avec un masque booléen dans ce cas, puisque la liste des indices est plus courte d'un millier. En fait mesurer la performance est bien sûr à vous.

+0

+1 Battez-moi. J'ajouterai simplement qu'il existe plusieurs options pour ce faire et la meilleure pratique consiste à comparer chaque élément si cette partie de votre code est un goulot d'étranglement. En général, je trouve que le tranchage est très rapide, surtout si le ratio est 1/1000. – JoshAdel

Questions connexes