Search code examples
pythonscipy-optimize

scipy.optimize.curve_fit() failed to fit a exponential function


I'm trying to fit a exponential function by using scipy.optimize.curve_fit()(The example data and code as following). But it always shows a RuntimeError like this: RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 5000. I'm not sure where I'm going wrong.

import numpy as np
from scipy.optimize import curve_fit

x = np.arange(-1, 1, .01)
param1 = [-1, 2, 10, 100]
fit_func = lambda x, a, b, c, d: a * np.exp(b * x + c) + d
y = fit_func(x, *param1)
popt, _ = curve_fit(fit_func, x, y, maxfev=5000)

Solution

  • This is almost certainly due to the initial guess for the parameters.

    You don't pass an initial guess to curve_fit, which means it defaults to a value of 1 for every parameter. Unfortunately, this is a terrible guess in your case. The function of interest is an exponential, one property of which is that the derivative is also an exponential. So all derivatives (first-order, second-order, etc) will be not just wrong, but have the wrong sign. This means the optimizer will have a very difficult time making progress.

    You can solve this by giving the optimizer just a smidge of help. Since you know all your data is negative, you could just pass -1 as an initial guess for the first parameter (the scale or amplitude of the function). This alone is enough to for the optimizer to arrive at a reasonable guess.

    p0 = (-1, 1, 1, 1)
    popt, _ = curve_fit(x, y, p0=p0, maxfev=5000)
    fig, ax = plt.subplots()
    ax.plot(x, y, label="Data", color="k")
    ax.plot(x, fit_func(x, *popt), color="r", linewidth=3.0, linestyle=":", label="Fitted")
    fig.tight_layout()
    

    You should see something like this:enter image description here