John Doe
John Doe

Reputation: 185

Sympy TypeError when using scipy.stats normal cdf

Why does Sympy throw a Type error when I use the scipy.stats.norm? How can I solve the equation?

from sympy import Eq, Symbol, solve, Piecewise
from scipy.stats import norm
import numpy as np

x = Symbol('x')
eqn = Eq((x-0.2)/0.3, norm.cdf((np.log(100/110) + x**2/2)/x))

print(solve(eqn))

Output:

TypeError: cannot determine truth value of Relational

Upvotes: 1

Views: 503

Answers (1)

user6655984
user6655984

Reputation:

Symbolic setup

If you are looking for symbolic solutions, use symbolic functions: e.g., SymPy's log not NumPy's log. The normal CDF is also available from SymPy's stats module as cdf(Normal("x", 0, 1)). The correct SymPy setup would be this:

from sympy import Eq, Rational, Symbol, log
from sympy.stats import cdf, Normal
eqn = Eq((x-Rational('0.2'))/Rational('0.3'), cdf(Normal("x", 0, 1))(log(Rational(100, 110)) + x**2/2)/x)

Notice that I put Rational('0.2') where you had 0.2. The distinction between rationals and floats is important for symbolic math. The equation now looks good from the formal point of view:

Eq(10*x/3 - 2/3, (erf(sqrt(2)*(x**2/2 - log(11) + log(10))/2)/2 + 1/2)/x)

Unfortunately it also looks hopeless: there's no closed form solution for things like that, involving a transcendental function equated to a polynomial. Naturally, solve(eqn) will fail. So all of the above does is demonstrate correct use of SymPy, but it doesn't change the fact that there is no symbolic solution.

Numeric solution

To solve this numerically, do the opposite: drop the SymPy parts and import fsolve from SciPy.

from scipy.stats import norm
from scipy.optimize import fsolve
import numpy as np

f = lambda x: (x-0.2)/0.3 - norm.cdf((np.log(100/110) + x**2/2)/x)
print(fsolve(f, 1))   # 1 is a random initial guess

The answer is 0.33622392.

Upvotes: 5

Related Questions