为什么我无法使用scipy.optimize.curve_fit为这些数据拟合sigmoid函数?

时间:2015-01-26 23:00:50

标签: python numpy scipy

使用下面的代码,我无法在我的数据集中使用sigmoid函数。 但是,如果我在下面的代码中添加了偏移量t = x + 50 -x0,那么它非常合适。

x0不应该照顾合适的人吗?


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

listA = np.array([-110,-105,-100,-95,-90,-85,-80,-75,-70,-65,-60,-55,-50,-45])
listB = np.array([1,1,1,1,0.926470588,0.852941176,0.616803279,0.371212121,
                  0.191066998,0.088565022,0.06684492,0.019855596,0.015517241,0])

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

popt, pcov = curve_fit(sigmoid, listA, listB)
print popt ,pcov    

x = np.linspace(-110,-45,50)

y = sigmoid(x, *popt)

pylab.plot(listA, listB, 'o', label='data')
pylab.plot(x,y, label='fit')
pylab.ylim(-0.05, 1.05)
pylab.legend(loc='best')
pylab.show()

2 个答案:

答案 0 :(得分:3)

您正在遇到初始条件敏感度的经典案例。 curve_fit函数接受关键字参数p0,可让您为函数的自由参数选择初始“猜测”(在您的情况下为x0k,和y0)。

如果未提供p0,则scipy会假定所有参数will start at one。对于你的函数,这意味着sigmoid的分母将非常接近于零,因此函数值会爆炸。这会使解算器混淆并导致解决方案不佳。

不幸的是,这个问题没有一个解决方案,因为它需要了解你想要适应的功能的动态。在您的情况下,提供p0 (-30, 1, 0)将允许求解器收敛到一个合适的解决方案。

答案 1 :(得分:3)

这是因为问题涉及到大量数字,使曲线拟合算法快速分化。

p0的(默认)初始猜测curve_fit是所有1的数组:

  

p0:无,标量或M长度序列       初步猜测参数。如果是None,那么最初       值将全部为1(如果函数的参数数量       可以使用内省来确定,否则就是ValueError       被提出。)

表示您的问题[1,1,1]。使用您的第一个x0值-110,这将导致指数的参数为​​:-1 * (-110-1),从而导致np.exp(111) 巨大数字,远远大于它被添加到的常数1。即使对于x0的初始猜测的小变化,结果也是与y0求和的分数几乎为零。这就是为什么你也会看到问题的原因popt会返回[1, 1, .51]:算法在x0中找不到微小的变化,对其产生重大影响结果(y)。

解决方案确实提供了一个不错的猜测。算法将用于参数的变化也取决于这些参数的大小。提供[-45, 1, 1]也会产生一个很好的解决方案,-90的初始猜测x0也是如此:只需确保水平偏移量至少为"关闭"到独立变量的值(在你的情况下为listA的值)。