So geben Sie 0 mit Division durch Null zurück

100

Ich versuche, eine elementweise Teilung in Python durchzuführen, aber wenn eine Null angetroffen wird, muss der Quotient nur Null sein.

Beispielsweise:

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

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

Ich könnte immer nur eine for-Schleife durch meine Daten verwenden, aber um die Optimierungen von numpy wirklich zu nutzen, muss die Divide-Funktion 0 bei Fehlern durch Division durch Null zurückgeben, anstatt den Fehler zu ignorieren.

Wenn mir nichts fehlt, scheint es nicht so, als ob numpy.seterr () bei Fehlern Werte zurückgeben kann. Hat jemand andere Vorschläge, wie ich das Beste aus Numpy herausholen kann, während ich meine eigene Division durch Null-Fehlerbehandlung setze?

hlin117
quelle
In meiner Python-Version (Python 2.7.11 | Continuum Analytics, Inc.) ist dies genau die Ausgabe, die Sie erhalten. Mit einer Warnung.
Ramon Martinez
Die prägnanteste richtige Antwort ist stackoverflow.com/a/37977222/2116338
mrplants

Antworten:

180

In numpy v1.7 + können Sie die Option "where" für ufuncs nutzen . Sie können Dinge in einer Zeile erledigen und müssen sich nicht mit dem fehlerhaften Kontextmanager befassen.

>>> 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]

In diesem Fall wird die Divisionsberechnung überall dort durchgeführt, wo 'b nicht gleich Null ist. Wenn b gleich Null ist, bleibt es unverändert gegenüber dem Wert, den Sie ursprünglich im Argument 'out' angegeben haben.

DStauffman
quelle
2
Wenn aund / oder bganzzahlige Arrays sein könnten, dann ist es das gleiche Konzept, Sie müssen nur explizit den richtigen Ausgabetyp c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
festlegen
out=np.zeros_like(a)ist kritisch, wie in der kommentierten Zeile angegeben.
Jonatan Öström
1
Wenn ich benutze np.divide(a, b, out=np.zeros_like(a), where=b!=0), bekomme ich den Fehler Assigning to function call which doesn't return. Das Seltsame ist, ich benutze es zweimal und der Fehler tritt nur einmal auf.
Jelmer Mulder
45

Aufbauend auf der Antwort von @Franck Dernoncourt, die -1/0 korrigiert:

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
quelle
Danke, ich habe diesen Fehler mit dem Code von @Frank Dernoncourt nicht einmal entdeckt.
hlin117
Hallo, ich versuche Array-Mathematik zu betreiben und möchte, dass 0/0 zu 0 führt, aber ich möchte auch np.NaN in meinen Berechnungen ignorieren. Wird das dafür funktionieren? Ich versuche auch zu verstehen. Was macht c [~ np.isfinite (c)] = 0? Ich habe ~ in Python noch nie benutzt. Wofür ist das? Vielen Dank
user20408
@ user20408, ~invertiert Trueund Falsein numpy Arrays : print ~ np.array([ True, False, False ]). c[ ~ np.isfinite( c )] = 0bedeutet: Finden Sie die Positionen, an denen ces endlich ist, invertieren Sie die Positionen , mit denen sie NICHT endlich sind ~, und setzen Sie die nicht-endlichen Werte auf 0. Siehe auch stackoverflow.com/search?q=[numpy‹+"boolean+indexing "
denis
42

Aufbauend auf den anderen Antworten und Verbesserung auf:

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))

Ausgabe:

c: [ 0.          0.          0.          1.          0.66666667]
Franck Dernoncourt
quelle
2
Gute Arbeit für die Überprüfung 0/0sowie 1/0Fehler.
hlin117
Ich habe Ihre Methode mit den Beispiel-Arrays ausprobiert, die in DStauffmans Antwort angegeben sind, und es scheint sehr hohe Zahlen anstelle von np.inf zu ergeben, was beim Endergebnis bleibt
Gal Avineri
Ich würde diesen Ansatz entmutigen. Wenn entweder aoder benthält NaN, gibt Ihre Lösung plötzlich 0als Ergebnis. Dies kann Fehler in Ihrem Code leicht verbergen und ist absolut unerwartet.
DerWeh
Laut dem kürzlich erschienenen numpy-Handbuch nimmt nan_to_num () Werte, um positive inf und negative inf zu ersetzen. numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)ist die Unterschrift.
Craig Hicks
18

Einzeiler (wirft Warnung)

np.nan_to_num(array1 / array2)
Ulf Aslak
quelle
13

Versuchen Sie es in zwei Schritten. Zuerst teilen, dann ersetzen.

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

Die numpy.errstateZeile ist optional und verhindert nur, dass Numpy Sie über den "Fehler" der Division durch Null informiert, da Sie dies bereits beabsichtigen und diesen Fall behandeln.

Pi Marillion
quelle
5
Sie sollten die Teilung wahrscheinlich im Kontext durchführennp.errstate(divide='ignore'):
Warren Weckesser
@WarrenWeckesser Messepunkt. Ich habe die Antwort so bearbeitet, dass sie den Kontext enthält. divide='warn'könnte auch nützlich sein, wenn er / sie noch benachrichtigt werden möchte.
Pi Marillion
2

Sie können auch basierend auf ersetzen inf, nur wenn die Array-d-Typen gemäß dieser Antwort Floats sind :

>>> 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
quelle
0

Eine Antwort, die ich bei der Suche nach einer verwandten Frage gefunden habe, war die Manipulation der Ausgabe basierend darauf, ob der Nenner Null war oder nicht.

Angenommen arrayAund arrayBinitialisiert wurde, sondern arrayBhat einige Nullen. Wir könnten Folgendes tun, wenn wir arrayC = arrayA / arrayBsicher rechnen wollen .

In diesem Fall setze ich die Zelle immer dann, wenn ich in einer der Zellen eine Division durch Null habe, auf gleich myOwnValue, was in diesem Fall Null wäre

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

Fußnote: Rückblickend ist diese Zeile sowieso nicht erforderlich, da sie arrayC[i]auf Null instanziiert wird. Aber wenn das der Fall wäremyOwnValue != 0 wäre, würde diese Operation etwas bewirken.

hlin117
quelle
0

Eine andere erwähnenswerte Lösung:

>>> 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
quelle