Je dois créer un polynôme de Lagrange en Python pour un projet que je fais. Je fais un style barycentrique pour éviter d'utiliser une boucle for explicite par opposition à un style de différence divisée de Newton. Le problème que j'ai est que je dois attraper une division par zéro, mais Python (ou peut-être numpy) en fait juste un avertissement au lieu d'une exception normale.
Donc, ce que j'ai besoin de savoir comment faire est d'attraper cet avertissement comme s'il s'agissait d'une exception. Les questions connexes que j'ai trouvées sur ce site n'ont pas reçu de réponse de la manière dont j'avais besoin. Voici mon 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.
Lorsque ce code est exécuté, la sortie que j'obtiens est:
Warning: divide by zero encountered in int_scalars
C'est l'avertissement que je veux attraper. Cela devrait se produire dans la compréhension de la liste.
Warning: ...
? Essayer des choses commenp.array([1])/0
moiRuntimeWarning: ...
en sortie.Réponses:
Il semble que votre configuration utilise l'
print
option pournumpy.seterr
:Cela signifie que l'avertissement que vous voyez n'est pas un véritable avertissement, mais que ce n'est que quelques caractères imprimés
stdout
(voir la documentation pourseterr
). Si vous voulez l'attraper, vous pouvez:numpy.seterr(all='raise')
qui lèvera directement l'exception. Cela change cependant le comportement de toutes les opérations, donc c'est un assez gros changement de comportement.numpy.seterr(all='warn')
, qui transformera l'avertissement imprimé en un véritable avertissement et vous pourrez utiliser la solution ci-dessus pour localiser ce changement de comportement.Une fois que vous avez réellement un avertissement, vous pouvez utiliser le
warnings
module pour contrôler la façon dont les avertissements doivent être traités:Lisez attentivement la documentation
filterwarnings
car elle vous permet de filtrer uniquement l'avertissement que vous souhaitez et dispose d'autres options. J'envisagerais également de regardercatch_warnings
quel est un gestionnaire de contexte qui réinitialise automatiquement lafilterwarnings
fonction d' origine :la source
RuntimeWarning
. Mise à jour de la réponse.RuntimeWarning
est levé. Le problème peut être que votre configuration numpy utilise l'print
option, qui imprime simplement l'avertissement mais ce n'est pas un vrai avertissement géré par lewarnings
module ... Si tel est le cas, vous pouvez essayer d'utilisernumpy.seterr(all='warn')
et réessayer.numpy
, vous ne pouvez pas utilisernumpy.seterr(all='error')
,error
doit l'êtreraise
.Pour ajouter un peu à la réponse de @ Bakuriu:
Si vous savez déjà où l'avertissement est susceptible de se produire, il est souvent plus propre d'utiliser le
numpy.errstate
gestionnaire de contexte, plutôt que celuinumpy.seterr
qui traite tous les avertissements ultérieurs du même type de la même manière, quel que soit l'endroit où ils se produisent dans votre code:Éditer:
Dans mon exemple original, j'avais
a = np.r_[0]
, mais apparemment il y avait un changement dans le comportement de numpy tel que la division par zéro est gérée différemment dans les cas où le numérateur est entièrement zéros. Par exemple, dans numpy 1.16.4:Les messages d'avertissement correspondants sont également différents:
1. / 0.
est enregistré commeRuntimeWarning: divide by zero encountered in true_divide
, alors que0. / 0.
est enregistré commeRuntimeWarning: invalid value encountered in true_divide
. Je ne sais pas pourquoi exactement ce changement a été effectué, mais je soupçonne que cela a à voir avec le fait que le résultat de0. / 0.
n'est pas représentable sous forme de nombre (numpy renvoie un NaN dans ce cas) alors que1. / 0.
et-1. / 0.
return + Inf et -Inf respectivement , conformément à la norme IEE 754.Si vous voulez intercepter les deux types d'erreur, vous pouvez toujours passer
np.errstate(divide='raise', invalid='raise')
, ouall='raise'
si vous voulez lever une exception sur n'importe quel type d'erreur en virgule flottante.la source
FloatingPointError
, nonZeroDivisionError
.Python 3.6.3
avecnumpy==1.16.3
. Pourriez-vous le mettre à jour s'il vous plaît?Pour élaborer sur la réponse de @ Bakuriu ci-dessus, j'ai trouvé que cela me permettait d'attraper un avertissement d'exécution de la même manière que j'attraperais un avertissement d'erreur, en imprimant l'avertissement bien:
Vous pourrez probablement jouer avec le placement du placement warnings.catch_warnings () en fonction de la taille d'un parapluie que vous voulez lancer avec des erreurs de capture de cette façon.
la source
Supprimez warnings.filterwarnings et ajoutez:
la source