Tengo que hacer un polinomio de Lagrange en Python para un proyecto que estoy haciendo. Estoy haciendo un estilo baricéntrico para evitar el uso de un bucle for explícito en lugar del estilo de diferencia dividida de Newton. El problema que tengo es que necesito atrapar una división por cero, pero Python (o quizás numpy) solo lo convierte en una advertencia en lugar de una excepción normal.
Entonces, lo que necesito saber hacer es captar esta advertencia como si fuera una excepción. Las preguntas relacionadas con esto que encontré en este sitio no fueron respondidas de la manera que necesitaba. Aquí está mi código:
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.
Cuando se ejecuta este código, el resultado que obtengo es:
Warning: divide by zero encountered in int_scalars
Esa es la advertencia que quiero atrapar. Debe ocurrir dentro de la lista de comprensión.

Warning: ...? Probar cosas comonp.array([1])/0me saleRuntimeWarning: ...como salida.Respuestas:
Parece que su configuración está utilizando la
printopción paranumpy.seterr:Esto significa que la advertencia que ve no es una advertencia real, sino solo algunos caracteres impresos
stdout(consulte la documentación paraseterr). Si quieres atraparlo puedes:numpy.seterr(all='raise')que aumentará directamente la excepción. Sin embargo, esto cambia el comportamiento de todas las operaciones, por lo que es un cambio bastante grande en el comportamiento.numpy.seterr(all='warn'), que transformará la advertencia impresa en una advertencia real y podrá utilizar la solución anterior para localizar este cambio de comportamiento.Una vez que tenga una advertencia, puede usar el
warningsmódulo para controlar cómo se deben tratar las advertencias:Lea atentamente la documentación
filterwarningsya que le permite filtrar solo la advertencia que desea y tiene otras opciones. También consideraría mirarcatch_warningscuál es un administrador de contexto que restablece automáticamente lafilterwarningsfunción original :fuente
RuntimeWarning. Se actualizó la respuesta.RuntimeWarningse plantea a. El problema podría ser que su configuración numpy está utilizando laprintopción, que simplemente imprime la advertencia pero no es una advertencia real manejada por elwarningsmódulo ... Si este es el caso, puede intentar usarlonumpy.seterr(all='warn')e intentarlo nuevamente.numpy, no se puede usarnumpy.seterr(all='error'),errordebe serraise.Para agregar un poco a la respuesta de @ Bakuriu:
Si ya sabe dónde es probable que ocurra la advertencia, a menudo es más limpio usar el
numpy.errstateadministrador de contexto, en lugar denumpy.seterrtratar todas las advertencias posteriores del mismo tipo, independientemente de dónde ocurran dentro de su código:Editar:
En mi ejemplo original
a = np.r_[0], sí, pero aparentemente hubo un cambio en el comportamiento de numpy de tal manera que la división por cero se maneja de manera diferente en los casos en que el numerador es todo ceros. Por ejemplo, en numpy 1.16.4:Los mensajes de advertencia correspondientes también son diferentes:
1. / 0.se registra comoRuntimeWarning: divide by zero encountered in true_divide, mientras que0. / 0.se registra comoRuntimeWarning: invalid value encountered in true_divide. No estoy seguro de por qué se realizó exactamente este cambio, pero sospecho que tiene que ver con el hecho de que el resultado de0. / 0.no es representable como un número (numpy devuelve un NaN en este caso) mientras que1. / 0.y-1. / 0.devuelve + Inf y -Inf respectivamente , según el estándar IEE 754.Si desea detectar ambos tipos de error, siempre puede pasar
np.errstate(divide='raise', invalid='raise'), oall='raise'si desea generar una excepción en cualquier tipo de error de coma flotante.fuente
FloatingPointError, noZeroDivisionError.Python 3.6.3connumpy==1.16.3. ¿Podrías actualizarlo por favor?Para profundizar en la respuesta de @ Bakuriu anterior, descubrí que esto me permite captar una advertencia de tiempo de ejecución de una manera similar a la que detectaría una advertencia de error, imprimiendo la advertencia muy bien:
Probablemente podrás jugar con la colocación de la colocación warnings.catch_warnings () dependiendo de qué tan grande de paraguas quieras lanzar con errores de captura de esta manera.
fuente
Elimine warnings.filterwarnings y agregue:
fuente