Ich muss ein Lagrange-Polynom in Python für ein Projekt erstellen, das ich gerade mache. Ich mache einen baryzentrischen Stil, um zu vermeiden, dass eine explizite for-Schleife verwendet wird, im Gegensatz zu einem Newton-Stil mit geteiltem Unterschied. Das Problem, das ich habe, ist, dass ich eine Division durch Null abfangen muss, aber Python (oder vielleicht Numpy) macht es nur zu einer Warnung anstelle einer normalen Ausnahme.
Ich muss also wissen, wie ich diese Warnung abfangen soll, als wäre es eine Ausnahme. Die diesbezüglichen Fragen, die ich auf dieser Website gefunden habe, wurden nicht so beantwortet, wie ich es brauchte. Hier ist mein Code:
import numpy as np
import matplotlib.pyplot as plt
import warnings
class Lagrange:
def __init__(self, xPts, yPts):
self.xPts = np.array(xPts)
self.yPts = np.array(yPts)
self.degree = len(xPts)-1
self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])
def __call__(self, x):
warnings.filterwarnings("error")
try:
bigNumerator = np.product(x - self.xPts)
numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
return sum(numerators/self.weights*self.yPts)
except Exception, e: # Catch division by 0. Only possible in 'numerators' array
return yPts[np.where(xPts == x)[0][0]]
L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2
L(1) # This should catch an error, then return 1.
Wenn dieser Code ausgeführt wird, erhalte ich folgende Ausgabe:
Warning: divide by zero encountered in int_scalars
Das ist die Warnung, die ich fangen möchte. Es sollte innerhalb des Listenverständnisses auftreten.
Warning: ...
? Versuche Dinge wienp.array([1])/0
ich bekommeRuntimeWarning: ...
als Ausgabe.Antworten:
Es scheint, dass Ihre Konfiguration die
print
Option verwendet fürnumpy.seterr
:Dies bedeutet, dass die Warnung, die Sie sehen, keine echte Warnung ist, sondern nur einige Zeichen, auf die gedruckt wird
stdout
(siehe Dokumentation fürseterr
). Wenn Sie es fangen wollen, können Sie:numpy.seterr(all='raise')
diese Option, um die Ausnahme direkt auszulösen. Dies ändert jedoch das Verhalten aller Vorgänge, sodass sich das Verhalten ziemlich stark ändert.numpy.seterr(all='warn')
diese Option, um die gedruckte Warnung in eine echte Warnung umzuwandeln, und Sie können die oben beschriebene Lösung verwenden, um diese Verhaltensänderung zu lokalisieren.Sobald Sie tatsächlich eine Warnung erhalten haben, können Sie mit dem
warnings
Modul steuern, wie die Warnungen behandelt werden sollen:Lesen Sie die Dokumentation sorgfältig durch,
filterwarnings
da Sie nur die gewünschte Warnung filtern können und andere Optionen haben. Ich würde auch überlegen,catch_warnings
welcher Kontextmanager die ursprünglichefilterwarnings
Funktion automatisch zurücksetzt :quelle
RuntimeWarning
. Die Antwort wurde aktualisiert.RuntimeWarning
ausgelöst wird. Das Problem könnte sein, dass Ihre Numpy-Konfiguration dieprint
Option verwendet, die einfach die Warnung druckt, aber keine echte Warnung ist, die vomwarnings
Modul verarbeitet wird. In diesem Fall können Sie versuchen,numpy.seterr(all='warn')
sie erneut zu verwenden.numpy
kann man nicht verwendennumpy.seterr(all='error')
,error
muss seinraise
.Um ein wenig zu @ Bakurius Antwort hinzuzufügen:
Wenn Sie bereits wissen, wo die Warnung wahrscheinlich auftritt, ist es häufig sauberer, den
numpy.errstate
Kontextmanager zu verwenden , alsnumpy.seterr
alle nachfolgenden Warnungen desselben Typs gleich zu behandeln, unabhängig davon, wo sie in Ihrem Code auftreten:Bearbeiten:
In meinem ursprünglichen Beispiel hatte ich
a = np.r_[0]
, aber anscheinend gab es eine Änderung im Verhalten von numpy, so dass die Division durch Null in Fällen, in denen der Zähler nur Null ist, anders gehandhabt wird. Zum Beispiel in numpy 1.16.4:Die entsprechenden Warnmeldungen sind ebenfalls unterschiedlich:
1. / 0.
wird als protokolliertRuntimeWarning: divide by zero encountered in true_divide
, während0. / 0.
als protokolliert wirdRuntimeWarning: invalid value encountered in true_divide
. Ich bin nicht sicher, warum genau diese Änderung vorgenommen wurde, aber ich vermute, dass dies damit zusammenhängt, dass das Ergebnis von0. / 0.
nicht als Zahl dargestellt werden kann (numpy gibt in diesem Fall eine NaN zurück), während1. / 0.
und-1. / 0.
+ Inf bzw. -Inf zurückgibt gemäß dem IEE 754-Standard.Wenn Sie beide Fehlertypen abfangen möchten, können Sie diese jederzeit übergeben
np.errstate(divide='raise', invalid='raise')
oderall='raise'
eine Ausnahme für Gleitkommafehler jeglicher Art auslösen.quelle
FloatingPointError
nichtZeroDivisionError
.Python 3.6.3
mitnumpy==1.16.3
. Könnten Sie es bitte aktualisieren?Um auf die Antwort von @ Bakuriu oben einzugehen, habe ich festgestellt, dass ich auf diese Weise eine Laufzeitwarnung abfangen kann, ähnlich wie ich eine Fehlerwarnung abfangen würde, indem ich die Warnung schön ausdrucke:
Sie werden wahrscheinlich in der Lage sein, mit dem Platzieren der Platzierung von warnings.catch_warnings () herumzuspielen, je nachdem, wie groß ein Regenschirm sein soll, den Sie auf diese Weise mit abfangenden Fehlern besetzen möchten.
quelle
Entfernen Sie warnings.filterwarnings und fügen Sie hinzu:
quelle