In my situation, the objective function is a numerical process contains a root finding process for an equation by bisection method.
With certain set of parameters, the equation does not have root for a intermediate variable. I thought making the bisection root finding routine return None can solve such problem.
As the object function with a set of date being regressed by scipy.optimize.curve_fit with p0 separate by this situation in between, error is then stop the process.
To study this case, a simplified case is shown.
import numpy as np
#Define object function:
def f(x,a1,a2):
if a1 < 0:
return None
elif a2 < 0:
return np.inf
else:
return a1 * x**2 + a2
#Making data:
x = np.linspace(-5,5,10)
i = 0
y = np.empty_like(x)
for xi in x:
y[i] = f(xi,1,1)
i += 1
import scipy.optimize as sp
para,pvoc = sp.curve_fit(f,x,y,p0=(-1,1))
#TypeError: unsupported operand type(s) for -: 'NoneType' and 'float'
para,pvoc = sp.curve_fit(f,x,y,p0=(1,-1))
#RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 600.
I also tried inf, and it is obviously not working.
What should I return to continue the curve_fit process?
Imagine it is trying to converge, what happen does the curve_fit do when it meets such situation.
Additional thinking:
I tried the try...except... to ignore the error and also simulate a case that the p0 is in a solvable range, but will pass the unsolvable segment to the true fit.
import numpy as np
def f(x,a1,a2):
if a1 < 0:
return None
elif a1 < 2:
return a1 * x**2 + a2
elif a2 < 0:
return np.inf
else:
return a1 * x**2 + a2
def ff(x,a1,a2):
output = f(x,a1,a2)
if output == None:
return 0
else:
return output
x = np.linspace(-5,5,10)
i = 0
y = np.empty_like(x)
for xi in x:
y[i] = f(xi,1,1)
i += 1
import scipy.optimize as sp
#para,pvoc = sp.curve_fit(f,x,y,p0=(-1,1))
#TypeError: unsupported operand type(s) for -: 'NoneType' and 'float':
#para,pvoc = sp.curve_fit(f,x,y,p0=(1,-1))
try:
para,pvoc = sp.curve_fit(f,x,y,p0=(-3,1))
except TypeError:
pass
Obviously error was met during converging and had been reported and was excepted.
What should I do to continue the curve_fit with the original converging direction?
Even I can make concession, how can I tell the curve_fit to return the last attempt to the a1?
On the other hand, I tried put this try... except... in the object function to return 0 when there is the error.
The result is then as I expect:
para,pvoc = sp.curve_fit(ff,x,y,p0=(-3,1))
#OptimizeWarning: Covariance of the parameters could not be estimated
category=OptimizeWarning)
I think you want to take a different approach. That is, you have written your objective function to return
NoneorInfto signal when the value fora1ora2is out of bounds:a1<0anda2<0are not acceptable values for the objective function.If that is a correct interpretation of what you are trying to do, it would be better to place bounds on both
a1anda2so that the objective function never gets those values at all. To do that withcurve_fityou would need to create a tuple of arrays for lower and upper bounds, with an order matching yourp0, soAs an aside: I have no idea why you're using a starting value for
a1that is < 0, and so out of bounds. That seems like you're asking for trouble.For an even better experience setting bounds on fitting parameters, you might consider using the
lmfit, which would allow you to write:which will print out
Hope that helps.