Search code examples
pythonnumpymathematical-optimization

Least square optimization with bounds using scipy.optimize


I have a least square optimization problem that I need help solving. So far, I have some code that does the following function:

shankarFunc = lambda p, x: p[0] * (1 - np.exp(-1 * ((x / p[1]) ** p[2])))
errFunc = lambda p, x, y: shankarFunc(p, x) - y

x0 = [max(y), 100 / max(y), 1]

p1, success = optimize.leastsq(errFunc, x0, args=(x, y))

and this almost works for all cases. It doesn't converge for some data, so I need to do a least square fitting with bounds for the fitted parameters. I then noticed that optimize.minimize has bounds, and tried to use that instead (minimizing the error function).

shankarFunc = lambda p, x: p[0] * (1 - np.exp(-1 * ((x / p[1]) ** p[2])))
errFunc = lambda p, x, y: shankarFunc(p, x) - y

x0 = [max(y), 100 / max(y), 1]
b0 = (0, max(y) + 2)
b1 = (1e-4, 5)
b2 = (0, None)
p1 = optimize.minimize(errFunc, x0, args=(x, y), bounds=(b0, b1, b2))

This gives me problems, as it returns the following error:

  File "C:\Anaconda\lib\site-packages\scipy\optimize\optimize.py", line 610, in
approx_fprime
    grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
ValueError: setting an array element with a sequence.

I've tried any number of variations on the input, but can't get rid of that.

How can I get optimize.minimize to play along? Is there a better solution to add bounds to the solution?


Solution

  • minimize optimizes a scalar function, you return an array (as it is excepted for leastsq). To use minizmize try change your function to:

    errFunc = lambda p, x, y: np.sum((shankarFunc(p, x) - y)**2)
    

    You could also use lmfit http://lmfit.github.io/lmfit-py/ which allows to use leastsq with bound through transformations.