Fit sigmoid function ("S" shape curve) to data using Python

21,996

After great help from @Brenlla the code was modified to:

def sigmoid(x, L ,x0, k, b):
    y = L / (1 + np.exp(-k*(x-x0))) + b
    return (y)

p0 = [max(ydata), np.median(xdata),1,min(ydata)] # this is an mandatory initial guess

popt, pcov = curve_fit(sigmoid, xdata, ydata,p0, method='dogbox')

The parameters optimized are L, x0, k, b, who are initially assigned in p0, the point the optimization starts from.

  • L is responsible for scaling the output range from [0,1] to [0,L]
  • b adds bias to the output and changes its range from [0,L] to [b,L+b]
  • k is responsible for scaling the input, which remains in (-inf,inf)
  • x0 is the point in the middle of the Sigmoid, i.e. the point where Sigmoid should originally output the value 1/2 [since if x=x0, we get 1/(1+exp(0)) = 1/2].

And the result:

enter image description here

Share:
21,996
user88484
Author by

user88484

Updated on February 13, 2022

Comments

  • user88484
    user88484 over 2 years

    I'm trying to fit a sigmoid function to some data I have but I keep getting:ValueError: Unable to determine number of fit parameters.

    My data looks like this:

    enter image description here

    My code is:

    from scipy.optimize import curve_fit
    
    def sigmoid(x):
        return (1/(1+np.exp(-x)))
    
    popt, pcov = curve_fit(sigmoid, xdata, ydata, method='dogbox')
    

    Then I get:

    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-5-78540a3a23df> in <module>
          2     return (1/(1+np.exp(-x)))
          3 
    ----> 4 popt, pcov = curve_fit(sigmoid, xdata, ydata, method='dogbox')
    
    ~\Anaconda3\lib\site-packages\scipy\optimize\minpack.py in curve_fit(f, xdata, ydata, p0, sigma, absolute_sigma, check_finite, bounds, method, jac, **kwargs)
        685         args, varargs, varkw, defaults = _getargspec(f)
        686         if len(args) < 2:
    --> 687             raise ValueError("Unable to determine number of fit parameters.")
        688         n = len(args) - 1
        689     else:
    
    ValueError: Unable to determine number of fit parameters.
    

    I'm not sure why this does not work, it seems like a trivial action--> fit a curve to some point. The desired curve would look like this:

    enter image description here

    Sorry for the graphics.. I did it in PowerPoint...

    How can I find the best sigmoid ("S" shape) curve?

    UPDATE

    Thanks to @Brenlla I've changed my code to:

    def sigmoid(k,x,x0):
        return (1 / (1 + np.exp(-k*(x-x0))))
    
    popt, pcov = curve_fit(sigmoid, xdata, ydata, method='dogbox')
    

    Now I do not get an error, but the curve is not as desired:

    x = np.linspace(0, 1600, 1000)
    y = sigmoid(x, *popt)
    
    plt.plot(xdata, ydata, 'o', label='data')
    plt.plot(x,y, label='fit')
    plt.ylim(0, 1.3)
    plt.legend(loc='best')
    

    and the result is:

    enter image description here

    How can I improve it so it will fit the data better?

    UPDATE2

    The code is now:

    def sigmoid(x, L,x0, k, b):
        y = L / (1 + np.exp(-k*(x-x0)))+b
    

    But the result is still...

    enter image description here