Comment retourner 0 avec une division par zéro

102

J'essaie d'effectuer une division par élément en python, mais si un zéro est rencontré, j'ai besoin que le quotient soit juste zéro.

Par exemple:

array1 = np.array([0, 1, 2])
array2 = np.array([0, 1, 1])

array1 / array2 # should be np.array([0, 1, 2])

Je pourrais toujours utiliser une boucle for à travers mes données, mais pour vraiment utiliser les optimisations de numpy, j'ai besoin que la fonction de division renvoie 0 lors de la division par zéro erreur au lieu d'ignorer l'erreur.

Sauf si je manque quelque chose, il ne semble pas que numpy.seterr () puisse renvoyer des valeurs en cas d'erreurs. Quelqu'un a-t-il d'autres suggestions sur la façon dont je pourrais tirer le meilleur parti de numpy tout en définissant ma propre division par zéro gestion des erreurs?

hlin117
la source
Dans ma version python (Python 2.7.11 | Continuum Analytics, Inc.), c'est exactement la sortie que vous obtenez. Avec un avertissement.
Ramon Martinez
La bonne réponse la plus succincte est stackoverflow.com/a/37977222/2116338
mrplants

Réponses:

189

Dans numpy v1.7 +, vous pouvez profiter de l'option "where" pour ufuncs . Vous pouvez faire des choses en une seule ligne et vous n'avez pas à vous occuper du gestionnaire de contexte errstate.

>>> a = np.array([-1, 0, 1, 2, 3], dtype=float)
>>> b = np.array([ 0, 0, 0, 2, 2], dtype=float)

# If you don't pass `out` the indices where (b == 0) will be uninitialized!
>>> c = np.divide(a, b, out=np.zeros_like(a), where=b!=0)
>>> print(c)
[ 0.   0.   0.   1.   1.5]

Dans ce cas, il effectue le calcul de division n'importe où «où» b n'est pas égal à zéro. Lorsque b est égal à zéro, il reste inchangé par rapport à la valeur que vous lui avez initialement donnée dans l'argument «out».

DStauffman
la source
4
Si aet / ou bpeut être des tableaux d'entiers, alors c'est le même concept, il vous suffit de définir explicitement le type de sortie correct:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman
out=np.zeros_like(a)est critique, comme indiqué dans la ligne commentée.
Jonatan Öström le
1
Si j'utilise np.divide(a, b, out=np.zeros_like(a), where=b!=0), j'obtiens l'erreur Assigning to function call which doesn't return. La chose étrange est que je l'utilise deux fois et que l'erreur n'apparaît qu'une fois.
Jelmer Mulder
46

S'appuyant sur la réponse de @Franck Dernoncourt, corrigeant -1/0:

def div0( a, b ):
    """ ignore / 0, div0( [-1, 0, 1], 0 ) -> [0, 0, 0] """
    with np.errstate(divide='ignore', invalid='ignore'):
        c = np.true_divide( a, b )
        c[ ~ np.isfinite( c )] = 0  # -inf inf NaN
    return c

div0( [-1, 0, 1], 0 )
array([0, 0, 0])
denis
la source
Merci, je n'ai même pas attrapé ce bug avec le code de @Frank Dernoncourt.
hlin117 le
Bonjour, j'essaie de faire des calculs de tableau et je veux que 0/0 aboutisse à 0, mais je veux également ignorer np.NaN dans mes calculs. Cela fonctionnera-t-il pour cela? Aussi, j'essaye de comprendre. Que fait c [~ np.isfinite (c)] = 0? Je n'ai jamais utilisé ~ en python. Pourquoi est-ce? Merci
user20408
@ user20408, ~radiers Trueet Falsedans les tableaux numpy: print ~ np.array([ True, False, False ]). c[ ~ np.isfinite( c )] = 0signifie: trouver les positions où cest finie, inverser celles-ci en NON finies avec ~, et définir les valeurs non finies sur 0. Voir aussi stackoverflow.com/search?q=[numpyedral+"boolean+indexing "
denis
43

S'appuyer sur les autres réponses et améliorer:

Code:

import numpy as np

a = np.array([0,0,1,1,2], dtype='float')
b = np.array([0,1,0,1,3], dtype='float')

with np.errstate(divide='ignore', invalid='ignore'):
    c = np.true_divide(a,b)
    c[c == np.inf] = 0
    c = np.nan_to_num(c)

print('c: {0}'.format(c))

Production:

c: [ 0.          0.          0.          1.          0.66666667]
Franck Dernoncourt
la source
2
Bon travail pour vérifier 0/0ainsi que les 1/0erreurs.
hlin117
J'ai essayé votre méthode avec les exemples de tableaux donnés dans la réponse de DStauffman et cela semble entraîner des nombres très élevés au lieu de np.inf, qui reste au résultat final
Gal Avineri
Je découragerais cette approche. Si l'un aou l' autre bcontient NaN, votre solution donne soudainement 0en conséquence. Cela peut facilement masquer les erreurs dans votre code et est absolument inattendu.
DerWeh
Selon le récent manuel numpy, nan_to_num () prend des valeurs pour se substituer à inf positif et inf négatif également. numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)est la signature.
Craig Hicks
19

One-liner (jette un avertissement)

np.nan_to_num(array1 / array2)
Ulf Aslak
la source
13

Essayez de le faire en deux étapes. Division d'abord, puis remplacez.

with numpy.errstate(divide='ignore'):
    result = numerator / denominator
    result[denominator == 0] = 0

La numpy.errstateligne est facultative, et empêche simplement numpy de vous parler de l '"erreur" de division par zéro, puisque vous avez déjà l'intention de le faire et de gérer ce cas.

Pi Marillion
la source
5
Vous devriez probablement effectuer la division dans le contextenp.errstate(divide='ignore'):
Warren Weckesser
@WarrenWeckesser Fair point. J'ai modifié la réponse pour inclure le contexte. divide='warn'pourrait également être utile s'il / elle souhaitait toujours être notifié.
Pi Marillion
2

Vous pouvez également remplacer basé sur inf, uniquement si les dtypes de tableau sont des flottants, selon cette réponse :

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> c = a / b
>>> c
array([ inf,   2.,   1.])
>>> c[c == np.inf] = 0
>>> c
array([ 0.,  2.,  1.])
atomh33ls
la source
0

Une réponse que j'ai trouvée en recherchant une question connexe était de manipuler la sortie en fonction du fait que le dénominateur était zéro ou non.

Supposons arrayAet arrayBont été initialisés, mais arrayBont des zéros. Nous pourrions faire ce qui suit si nous voulons calculer en arrayC = arrayA / arrayBtoute sécurité.

Dans ce cas, chaque fois que j'ai une division par zéro dans l'une des cellules, je règle la cellule pour qu'elle soit égale à myOwnValue, ce qui dans ce cas serait égal à zéro

myOwnValue = 0
arrayC = np.zeros(arrayA.shape())
indNonZeros = np.where(arrayB != 0)
indZeros = np.where(arrayB = 0)

# division in two steps: first with nonzero cells, and then zero cells
arrayC[indNonZeros] = arrayA[indNonZeros] / arrayB[indNonZeros]
arrayC[indZeros] = myOwnValue # Look at footnote

Note de bas de page: rétrospectivement, cette ligne est de toute façon inutile, puisqu'elle arrayC[i]est instanciée à zéro. Mais si c'était le cas myOwnValue != 0, cette opération ferait quelque chose.

hlin117
la source
0

Une autre solution à mentionner:

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> b_inv = np.array([1/i if i!=0 else 0 for i in b])
>>> a*b_inv
array([0., 2., 1.])
T. Gwen
la source