Si j'ai un tableau comme
a = np.array([2, 3, -1, -4, 3])
Je veux mettre tous les éléments négatifs à zéro: [2, 3, 0, 0, 3]
. Comment le faire avec numpy sans explicite pour? J'ai besoin d'utiliser le a
modifié dans un calcul, par exemple
c = a * b
où b
est un autre tableau de la même longueur que l'original a
import numpy as np
from time import time
a = np.random.uniform(-1, 1, 20000000)
t = time(); b = np.where(a>0, a, 0); print ("1. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); b = a.clip(min=0); print ("2. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); a[a < 0] = 0; print ("3. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); a[np.where(a<0)] = 0; print ("4. ", time() - t)
a = np.random.uniform(-1, 1, 20000000)
t = time(); b = [max(x, 0) for x in a]; print ("5. ", time() - t)
a = a.clip(min=0)
Je ferais ceci:
a[a < 0] = 0
Si vous souhaitez conserver le a
d'origine et ne définir que les éléments négatifs à zéro dans une copie, vous pouvez d'abord copier le tableau:
c = a.copy()
c[c < 0] = 0
Une autre astuce consiste à utiliser la multiplication. Cela semble en fait être beaucoup plus rapide que toutes les autres méthodes ici. Par exemple
b = a*(a>0) # copies data
ou
a *= (a>0) # in-place zero-ing
J'ai exécuté des tests avec timeit, en pré-calculant le <et> car certains d'entre eux se modifient sur place et cela affecterait grandement les résultats. Dans tous les cas, a
était np.random.uniform(-1, 1, 20000000)
mais avec des négatifs déjà définis sur 0 mais L = a < 0
Et G = a > 0
Avant que a
ne soit modifié. Le clip
est relativement négativement impacté car il ne peut pas utiliser L
ou G
(cependant le calcul de ceux sur la même machine n'a pris que 17 ms chacun, donc ce n'est pas le cause principale de différence de vitesse).
%timeit b = np.where(G, a, 0) # 132ms copies
%timeit b = a.clip(min=0) # 165ms copies
%timeit a[L] = 0 # 158ms in-place
%timeit a[np.where(L)] = 0 # 122ms in-place
%timeit b = a*G # 87.4ms copies
%timeit np.multiply(a,G,a) # 40.1ms in-place (normal code would use `a*=G`)
Lorsque vous choisissez de pénaliser les méthodes sur place au lieu de clip
, les délais suivants apparaissent:
%timeit b = np.where(a>0, a, 0) # 152ms
%timeit b = a.clip(min=0) # 165ms
%timeit b = a.copy(); b[a<0] = 0 # 231ms
%timeit b = a.copy(); b[np.where(a<0)] = 0 # 205ms
%timeit b = a*(a>0) # 108ms
%timeit b = a.copy(); b*=a>0 # 121ms
Les méthodes non en place sont pénalisées de 20 ms (le temps nécessaire pour calculer a>0
Ou a<0
) Et les méthodes en place pénalisent 73 à 83 ms (il faut donc environ 53 à 63 ms pour faire b.copy()
).
Globalement, les méthodes de multiplication sont beaucoup plus rapides que clip
. S'il n'est pas en place, c'est 1.5x plus rapide. Si vous pouvez le faire sur place, c'est 2.75x plus rapide.
Utilisez où
a[numpy.where(a<0)] = 0
Et juste pour des raisons d'exhaustivité, je voudrais ajouter l'utilisation de la fonction Heaviside (ou une fonction de pas) pour obtenir un résultat similaire comme suit:
Disons pour la continuité que nous avons
a = np.array([2, 3, -1, -4, 3])
Ensuite, en utilisant une fonction pas à pas np.heaviside()
on peut essayer
b = a * np.heaviside(a, 0)
Notez quelque chose d'intéressant dans cette opération car les signes négatifs sont préservés! Pas très idéal pour la plupart des situations, je dirais.
Cela peut ensuite être corrigé par
b = abs(b)
C'est donc probablement un assez long chemin à parcourir sans invoquer de boucle.