Comment puis-je attraper un numpy avertissement comme c'est une exception (pas juste pour le test)?
Je dois faire un polynôme de Lagrange en Python pour un projet que je suis en train de faire. Je suis en train de faire un barycentriques le style d'éviter l'utilisation explicite d'une boucle for, par opposition à un Newton est divisé différence de style. Le problème que j'ai c'est que j'ai besoin d'attraper une division par zéro, mais en Python (ou peut-être numpy) il fait juste un avertissement au lieu d'une normale exception.
Donc, ce que j'ai besoin de savoir comment le faire est de prendre cet avertissement, comme si c'était une exception. Les questions liées à ce que j'ai trouvé sur ce site ont répondu à pas dans la façon 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é, le résultat que j'obtiens est:
Warning: divide by zero encountered in int_scalars
C'est l'avertissement que j'ai envie de l'attraper. Il devrait se produire à l'intérieur de la compréhension de liste.
- Êtes-vous bien sûr que c'est
Warning: ...
? Essayer des choses commenp.array([1])/0
- je obtenirRuntimeWarning: ...
en sortie. - Pas un doublon; NumPy a son propre avertissement de l'architecture sur le dessus de Pythons, qui peut être précisément contrôlée (voir la réponse par Bakuríu).
- Je corrige la position des mains et appris une nouvelle chose. J'ai supprimé mon commentaire d'origine pour éviter le déclenchement de l'insigne de la collection de la frénésie.
- Une autre approche que l'on pourrait utiliser est tout simplement de vérifier si le dénominateur est de 0 avant la division, ce qui évite la surcharge de jongler avec numpy du système d'alerte. (Bien que cela signifie probablement que vous avez à développer neat compréhension de liste dans une boucle de vérifier si l'un des dénominateurs est égale à zéro.)
Vous devez vous connecter pour publier un commentaire.
Il semble que votre configuration est à l'aide de la
print
option pournumpy.seterr
:Cela signifie que l'avertissement que vous voyez est pas un avertissement réel, mais c'est juste des caractères imprimés à
stdout
(voir la documentation deseterr
). Si vous voulez l'attraper, vous pouvez:numpy.seterr(all='raise')
qui va directement à lever l'exception. Toutefois, cela change le comportement de toutes les opérations, donc c'est vraiment un grand changement dans son comportement.numpy.seterr(all='warn')
, qui va transformer l'imprimé avertissement un avertissement réel et vous serez en mesure d'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 mises en garde doivent être traités:Lire attentivement la documentation de
filterwarnings
car elle permet de filtrer uniquement l'avertissement que vous voulez et a d'autres options. Je voudrais également envisager de chercher àcatch_warnings
qui est un gestionnaire de contexte qui entraîne la réinitialisation automatique de l'originalfilterwarnings
fonction:RuntimeWarning
. Mise à jour de la réponse.RuntimeWarning
est soulevée. Le problème est peut-être que votre numpy configuration à l'aide de laprint
option, qui imprime simplement l'avertissement, mais ce n'est pas un avertissement réel manipulé par lewarnings
module... Si c'est le cas vous pouvez essayer d'utilisernumpy.seterr(all='warn')
et essayez de nouveau.numpy
, vous ne pouvez pas utilisernumpy.seterr(all='error')
,error
doit êtreraise
.'error'
au lieu de cela, si j'ai écrit que, parce que j'ai été distrait.D'ajouter un peu d' @Bakuriu réponse:
Si vous savez déjà où l'avertissement est susceptible de se produire alors qu'il est souvent plus propre d'utiliser la
numpy.errstate
gestionnaire de contexte, plutôt que denumpy.seterr
qui traite de toutes les mises en garde du même type, la même quel que soit l'endroit où ils se produisent dans votre code:Edit:
Dans mon exemple j'ai eu
a = np.r_[0]
, mais apparemment, il y avait un changement dans numpy du comportement, tels que la division par zéro est traitée différemment dans les cas où le numérateur est tous des zéros. Par exemple, dans numpy 1.16.4:Le correspondant des messages d'avertissement 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 exactement pourquoi ce changement a été fait, mais je soupçonne que cela a à voir avec le fait que le résultat de0. /0.
n'est pas représentable comme un nombre (numpy renvoie NaN dans ce cas) alors que1. /0.
et-1. /0.
retour +Inf et -Inf, respectivement, par l'IEE 754 la norme.Si vous voulez attraper les deux types d'erreur, vous pouvez toujours passer
np.errstate(divide='raise', invalid='raise')
, ouall='raise'
si vous voulez soulever l'exception d'un tout sorte de virgule flottante erreur.FloatingPointError
, pasZeroDivisionError
.Python 3.6.3
avecnumpy==1.16.3
. Pourriez-vous le mettre à jour s'il vous plaît?D'élaborer sur @Bakuriu la réponse ci-dessus, j'ai trouvé que cela me permet de rattraper un moteur d'exécution d'avertissement d'une manière similaire à la façon dont je voudrais prendre un avertissement d'erreur, l'impression de l'avertissement de bien:
Vous aurez probablement être en mesure de jouer avec la mise en place des avertissements.catch_warnings() de placement en fonction de la taille d'un parapluie que vous voulez jeter par la capture des erreurs de cette façon.
Supprimer les avertissements.filterwarnings et d'ajouter: