web-dev-qa-db-fra.com

python: contourner la division par zéro

J'ai un grand ensemble de données de nombres à virgule flottante. Je les parcoure et évalue np.log(x) pour chacun d’eux. Je reçois

RuntimeWarning: divide by zero encountered in log

Je voudrais contourner cela et renvoyer 0 si cette erreur se produit.

Je pense définir une nouvelle fonction:

def safe_ln(x):
    #returns: ln(x) but replaces -inf with 0
    l = np.log(x)
    #if l = -inf:
    l = 0
    return l

En gros, j'ai besoin d'un moyen de vérifier que la sortie est -inf mais je ne sais pas comment procéder. Merci de votre aide!

17
Julia

Puisque la log pour x=0 est moins infinie, je voudrais simplement vérifier si la valeur d'entrée est égale à zéro et renvoyer ce que vous voulez là:

def safe_ln(x):
    if x <= 0:
        return 0
    return math.log(x)

EDIT: small edit: vous devez vérifier toutes les valeurs inférieures ou égales à 0.

EDIT 2 : np.log est bien sûr une fonction à calculer sur un tableau numpy. Pour les valeurs uniques, vous devez utiliser math.log. Voici à quoi ressemble la fonction ci-dessus avec numpy:

def safe_ln(x, minval=0.0000000001):
    return np.log(x.clip(min=minval))
22
Constantinius

Vous utilisez une fonction np, je peux donc sans risque supposer que vous travaillez sur un tableau numpy? Le moyen le plus efficace consiste à utiliser la fonction where au lieu d’une boucle for

myarray= np.random.randint(10,size=10)
result = np.where(myarray>0, np.log(myarray), 0)

sinon, vous pouvez simplement utiliser la fonction de journalisation, puis corriger le trou:

myarray= np.random.randint(10,size=10)
result = np.log(myarray)
result[result==-np.inf]=0

La fonction np.log retourne correctement -inf lorsqu'elle est utilisée avec une valeur de 0, alors êtes-vous sûr de vouloir renvoyer un 0? si, quelque part, vous devez revenir à la valeur d'origine, vous allez rencontrer un problème, en changeant des zéros en un ...

32
EnricoGiampieri

Tu peux le faire.

def safe_ln(x):
   try:
      l = np.log(x)
   except ZeroDivisionError:
      l = 0
   return l
3
Jeff

utiliser la gestion des exceptions:

In [27]: def safe_ln(x):
    try:
        return math.log(x)
    except ValueError:       # np.log(x) might raise some other error though
        return float("-inf")
   ....:     

In [28]: safe_ln(0)
Out[28]: -inf

In [29]: safe_ln(1)
Out[29]: 0.0

In [30]: safe_ln(-100)
Out[30]: -inf
1
Ashwini Chaudhary

La réponse donnée par Enrico est Nice, mais les deux solutions aboutissent à un avertissement:

RuntimeWarning: divide by zero encountered in log

En guise d'alternative, nous pouvons toujours utiliser la fonction where mais n'exécuter le calcul principal que s'il est approprié:

# alternative implementation -- a bit more typing but avoids warnings.
loc = np.where(myarray>0)
result2 = np.zeros_like(myarray, dtype=float)
result2[loc] =np.log(myarray[loc])

# answer from Enrico...
myarray= np.random.randint(10,size=10)
result = np.where(myarray>0, np.log(myarray), 0)

# check it is giving right solution:
print(np.allclose(result, result2))

Mon cas d'utilisation était pour la division, mais le principe est clairement le même:

x = np.random.randint(10, size=10)
divisor = np.ones(10,)
divisor[3] = 0 # make one divisor invalid

y = np.zeros_like(divisor, dtype=float)
loc = np.where(divisor>0) # (or !=0 if your data could have -ve values)
y[loc] = x[loc] / divisor[loc]
0
Bonlenfum

vous pourriez faire:

def safe_ln(x):
    #returns: ln(x) but replaces -inf with 0
    try:
        l = np.log(x)
    except RunTimeWarning:
        l = 0
    return l
0
Cameron Sparr