J'ai besoin de fonctions de logit et inverse logit de sorte que et voici les valeurs suivantes: p> testons les nombres négatifs p > Donc, mes questions sont: Quelle est la manière appropriée de mettre en œuvre ces fonctions afin que l'exigence et aussi (et je suis sûr que cela est connecté au premier), Pourquoi ma fonction est-elle plus stable avec des valeurs négatives, comparées aux positives? P> P> logit (inv_logit (n)) == n code>. J'utilise numpy et voici ce que j'ai:
logit (inv_logit (n)) == n code> tout
n code> dans une plage aussi large que possible (au moins [-1e4; 1e4)? p>
5 Réponses :
Vous courez contre les limites de précision pour un flotteur à double précision IEEE 754. Vous devrez utiliser des numéros et des opérations plus haut de précision si vous souhaitez une gamme plus grande et un domaine plus précis.
>>> 1 + np.exp(-37) 1.0 >>> 1 + decimal.Decimal(-37).exp() Decimal('1.000000000000000085330476257')
Utiliser
1.
Le paquet BigFloat avec des supports Explication de précision arbitraire flottante forte> points de points. P> 2.
Le symbolique premier, BigFloat: P> http://packages.python.org/bigfloat/ p> Voici un exemple simple: p> C'est vraiment lent. Vous voudrez peut-être envisager de restructurer votre problème et de faire des pièces analytiquement. Des cas comme ceux-ci sont rares dans de vrais problèmes - je suis curieux de savoir quel type de problème vous travaillez. P> Exemple Installation: P> from sympy import *
def inv_logit(p):
return exp(p) / (1 + exp(p))
def logit(p):
return log(p)- log(1 -p)
x=Symbol('x')
expr=logit(inv_logit(x))
# expr is now:
# -log(1 - exp(x)/(1 + exp(x))) + log(exp(x)/(1 + exp(x)))
# rewrite it: (there are many other ways to do this. read the doc)
# you may want to make an expansion (of some suitable kind) instead.
expr=cancel(powsimp(expr)).expand()
# it is now 'x'
# just evaluate any expression like this:
result=expr.subs(x,123.231)
# result is now an equation containing: 123.231
# to get the float:
result.evalf()
Il existe un moyen de mettre en œuvre les fonctions afin qu'elles soient stables dans un large éventail de valeurs, mais cela implique une distinction de cas en fonction de l'argument.
prendre par exemple la fonction inv_logit. Votre formule "np.exp (p) / (1 + np.exp (p))" est correcte mais débordera pour Big P. Si vous divisez le numérateur et le dénominateur de NP.EXP (P), vous obtenez l'expression équivalente p> la différence étant que celle-ci ne déborde pas de grand positif p. Il déborde toutefois de grosses valeurs négatives de p. Ainsi, une implémentation stable pourrait être la suivante: p> Il s'agit de la stratégie utilisée dans la bibliothèque liblinear (et éventuellement d'autres). p> p>
Ma variante de la réponse de Fabian Pedregosa:
def stables_inv_logit (x):
Retour 0.5 * (1. + np.sign (X) * (2.//(1. + np.exp (-np.abs (x))) - 1.)))
code> p>