Chris Spencer | 21 Sep 03:38 2010
Picon

Sigmoid Curve Fitting

Hi,

Does Scipy contain the ability to fit a sigmoid curve to a set of data points?

I found some Numpy code
(http://pingswept.org/2009/01/24/least-squares-polynomial-fitting-in-python/)
for fitting curves using the least squares method, but it only seems
to fit parabolas to my sigmoid data.

Regards,
Chris
Warren Weckesser | 21 Sep 05:54 2010

Re: Sigmoid Curve Fitting

  On 9/20/10 8:38 PM, Chris Spencer wrote:
> Hi,
>
> Does Scipy contain the ability to fit a sigmoid curve to a set of data points?
>
> I found some Numpy code
> (http://pingswept.org/2009/01/24/least-squares-polynomial-fitting-in-python/)
> for fitting curves using the least squares method, but it only seems
> to fit parabolas to my sigmoid data.
>

You can use curve_fit (scipy.optimize.curve_fit).

Which family of sigmoid functions do you want to use?
See http://en.wikipedia.org/wiki/Sigmoid_function for a few possibilities.

If, for example, you want to fit the following family to your data:

f(x) = 1/(1 + exp(-k*(x-x0)))

(which has two parameters, k and x0), you can do something like this:

-----
import numpy as np
import pylab
from scipy.optimize import curve_fit

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

Chris Spencer | 21 Sep 15:13 2010
Picon

Re: Sigmoid Curve Fitting

Thank you. Since that feature only appears to be in the bleeding-edge
version, it took me a while to track-down and compile all the
libraries on Ubuntu 10.04, but it works perfectly.

Regards,
Chris

On Mon, Sep 20, 2010 at 11:54 PM, Warren Weckesser
<warren.weckesser <at> enthought.com> wrote:
>  On 9/20/10 8:38 PM, Chris Spencer wrote:
>>
>> Hi,
>>
>> Does Scipy contain the ability to fit a sigmoid curve to a set of data
>> points?
>>
>> I found some Numpy code
>>
>> (http://pingswept.org/2009/01/24/least-squares-polynomial-fitting-in-python/)
>> for fitting curves using the least squares method, but it only seems
>> to fit parabolas to my sigmoid data.
>>
>
> You can use curve_fit (scipy.optimize.curve_fit).
>
> Which family of sigmoid functions do you want to use?
> See http://en.wikipedia.org/wiki/Sigmoid_function for a few possibilities.
>
> If, for example, you want to fit the following family to your data:
>
(Continue reading)

Chris Spencer | 21 Sep 17:24 2010
Picon

Re: Sigmoid Curve Fitting

Is it possible to get it to determine the asymptotes as well? It seems
to assume the curve will be bounded between y=0 and 1, whereas my data
can have arbitrary limits. I tried changing sigmoid() to:

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

but that only results in a curve of f(x)=0.5.

Regards,
Chris

On Mon, Sep 20, 2010 at 11:54 PM, Warren Weckesser
<warren.weckesser <at> enthought.com> wrote:
>  On 9/20/10 8:38 PM, Chris Spencer wrote:
>>
>> Hi,
>>
>> Does Scipy contain the ability to fit a sigmoid curve to a set of data
>> points?
>>
>> I found some Numpy code
>>
>> (http://pingswept.org/2009/01/24/least-squares-polynomial-fitting-in-python/)
>> for fitting curves using the least squares method, but it only seems
>> to fit parabolas to my sigmoid data.
>>
>
> You can use curve_fit (scipy.optimize.curve_fit).
(Continue reading)

Warren Weckesser | 21 Sep 18:16 2010

Re: Sigmoid Curve Fitting

  On 9/21/10 10:24 AM, Chris Spencer wrote:
> Is it possible to get it to determine the asymptotes as well? It seems
> to assume the curve will be bounded between y=0 and 1, whereas my data
> can have arbitrary limits. I tried changing sigmoid() to:
>
> def sigmoid(x, x0, k, a):
>     y = a * 1 / (1 + np.exp(-k*(x-x0)))
>     return y
>
> but that only results in a curve of f(x)=0.5.
>

The following is a variation that includes more parameters in the family 
of sigmoid functions.  But bear in mind, I chose this family of 
functions just as a demonstration of curve_fit.  I don't know if it 
makes sense to use this family for your data.  The appropriate family to 
use depends on the nature of the data.

-----
import numpy as np
import pylab
from scipy.optimize import curve_fit

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

xdata = np.array([0.0,   1.0,  3.0,  4.3,  7.0,   8.0,   8.5, 10.0,  
12.0, 14.0])
ydata = np.array([0.11, 0.12, 0.14, 0.21, 0.83,  1.45,   1.78,  1.9, 
(Continue reading)

Chris Spencer | 21 Sep 19:02 2010
Picon

Re: Sigmoid Curve Fitting

On Tue, Sep 21, 2010 at 12:16 PM, Warren Weckesser
<warren.weckesser <at> enthought.com> wrote:
> The following is a variation that includes more parameters in the family
> of sigmoid functions.  But bear in mind, I chose this family of
> functions just as a demonstration of curve_fit.  I don't know if it
> makes sense to use this family for your data.  The appropriate family to
> use depends on the nature of the data.

I see what you mean. That modification only fits a low-to-high
sigmoid, but that's close enough for me to adapt by reversing my data
set. Thank you for the excellent example.

Regards,
Chris
Chris Spencer | 21 Sep 20:04 2010
Picon

Re: Sigmoid Curve Fitting

I found this modification allows for the inversion of the estimated
sigmoid curve:

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

Regards,
Chris

On Tue, Sep 21, 2010 at 1:02 PM, Chris Spencer <chrisspen <at> gmail.com> wrote:
> On Tue, Sep 21, 2010 at 12:16 PM, Warren Weckesser
> <warren.weckesser <at> enthought.com> wrote:
>> The following is a variation that includes more parameters in the family
>> of sigmoid functions.  But bear in mind, I chose this family of
>> functions just as a demonstration of curve_fit.  I don't know if it
>> makes sense to use this family for your data.  The appropriate family to
>> use depends on the nature of the data.
>
> I see what you mean. That modification only fits a low-to-high
> sigmoid, but that's close enough for me to adapt by reversing my data
> set. Thank you for the excellent example.
>
> Regards,
> Chris
>
Warren Weckesser | 21 Sep 20:21 2010

Re: Sigmoid Curve Fitting


On 9/21/10 1:04 PM, Chris Spencer wrote:
> I found this modification allows for the inversion of the estimated
> sigmoid curve:
>
> def sigmoid(x, x0, k, a, c, d):
>      y = 1 / (1 + np.exp(-k*(x-x0)))
>      y = (1 - y)*(1 - d) + y*d
>      y = a * y + c
>      return y
>

A negative value of k "reverses" the sigmoid shape, so you shouldn't 
have to define a new function.  If you prefer to have k be positive, you 
could use

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

(I changed "-k" to "k".)

Warren

> Regards,
> Chris
>
> On Tue, Sep 21, 2010 at 1:02 PM, Chris Spencer<chrisspen <at> gmail.com>  wrote:
>> On Tue, Sep 21, 2010 at 12:16 PM, Warren Weckesser
>> <warren.weckesser <at> enthought.com>  wrote:
(Continue reading)

Chris Spencer | 21 Sep 20:30 2010
Picon

Re: Sigmoid Curve Fitting

Right, I noticed that negating k should theoretically have the same
effect. However, when I reversed your sample data (i.e. ydata =
ydata[::-1]), I was surprised to find that curve_fit gives me
f(x)=0.92 instead of a proper sigmoid curve. Adding my parameter seems
to work around this problem.

Regards,
Chris

On Tue, Sep 21, 2010 at 2:21 PM, Warren Weckesser
<warren.weckesser <at> enthought.com> wrote:
>
> On 9/21/10 1:04 PM, Chris Spencer wrote:
>> I found this modification allows for the inversion of the estimated
>> sigmoid curve:
>>
>> def sigmoid(x, x0, k, a, c, d):
>>      y = 1 / (1 + np.exp(-k*(x-x0)))
>>      y = (1 - y)*(1 - d) + y*d
>>      y = a * y + c
>>      return y
>>
>
>
> A negative value of k "reverses" the sigmoid shape, so you shouldn't
> have to define a new function.  If you prefer to have k be positive, you
> could use
>
> def sigmoid(x, x0, k, a, c):
>     y = a / (1 + np.exp(k*(x-x0))) + c
(Continue reading)

Warren Weckesser | 21 Sep 20:36 2010

Re: Sigmoid Curve Fitting

  On 9/21/10 1:30 PM, Chris Spencer wrote:
> Right, I noticed that negating k should theoretically have the same
> effect. However, when I reversed your sample data (i.e. ydata =
> ydata[::-1]), I was surprised to find that curve_fit gives me
> f(x)=0.92 instead of a proper sigmoid curve.

Ah, in that case, it can help to give curve_fit a better initial guess 
for the parameters.  For example, if I use

popt, pcov = curve_fit(sigmoid, xdata, ydata, p0=(1.0, -1.0, 1.0, 0.0))

with the original function, it works as expected.

Warren

>   Adding my parameter seems
> to work around this problem.
>
> Regards,
> Chris
>
> On Tue, Sep 21, 2010 at 2:21 PM, Warren Weckesser
> <warren.weckesser <at> enthought.com>  wrote:
>> On 9/21/10 1:04 PM, Chris Spencer wrote:
>>> I found this modification allows for the inversion of the estimated
>>> sigmoid curve:
>>>
>>> def sigmoid(x, x0, k, a, c, d):
>>>       y = 1 / (1 + np.exp(-k*(x-x0)))
>>>       y = (1 - y)*(1 - d) + y*d
(Continue reading)

Sturla Molden | 21 Sep 21:29 2010
Picon

Re: Sigmoid Curve Fitting

> Hi,
>
> Does Scipy contain the ability to fit a sigmoid curve to a set of data
> points?
>
> I found some Numpy code
> (http://pingswept.org/2009/01/24/least-squares-polynomial-fitting-in-python/)
> for fitting curves using the least squares method, but it only seems
> to fit parabolas to my sigmoid data.

scipy.optimize.leastsq can fit any non-linear regression curve using
Levenberg-Marquardt. You will have to supply a function that computes the
residuals, and optionally a function that returns their Jacobian unless
you want it estimated.

Sturla
Gökhan Sever | 21 Sep 22:31 2010
Picon

Re: Sigmoid Curve Fitting



On Tue, Sep 21, 2010 at 2:29 PM, Sturla Molden <sturla <at> molden.no> wrote:
scipy.optimize.leastsq can fit any non-linear regression curve using
Levenberg-Marquardt. You will have to supply a function that computes the
residuals, and optionally a function that returns their Jacobian unless
you want it estimated.

curve_fit is just a specific version of leastsq, right? From their documentation I see that they both employ the same nonlinear regression algorithm.   

--
Gökhan
_______________________________________________
SciPy-User mailing list
SciPy-User <at> scipy.org
http://mail.scipy.org/mailman/listinfo/scipy-user
Bruce Southey | 22 Sep 03:18 2010
Picon

Re: Sigmoid Curve Fitting

On Tue, Sep 21, 2010 at 2:29 PM, Sturla Molden <sturla <at> molden.no> wrote:
>> Hi,
>>
>> Does Scipy contain the ability to fit a sigmoid curve to a set of data
>> points?
>>
>> I found some Numpy code
>> (http://pingswept.org/2009/01/24/least-squares-polynomial-fitting-in-python/)
>> for fitting curves using the least squares method, but it only seems
>> to fit parabolas to my sigmoid data.
>
> scipy.optimize.leastsq can fit any non-linear regression curve using
> Levenberg-Marquardt. You will have to supply a function that computes the
> residuals, and optionally a function that returns their Jacobian unless
> you want it estimated.
>
> Sturla
>
Ignoring that you data is the opposite,  there are a lot of 'growth
curves'  such as Richard's (growth) curve or generalized logistic
function.
http://en.wikipedia.org/wiki/Generalised_logistic_function

Also, you can fit a linear model if your model can be linearized. The
downside is that the errors are multiplicative rather than additive.
For nonlinear models, it usually helps to standardize your data.

Bruce

Gmane