使用 Python 将 sigmoid 函数(“S”形曲线)拟合到数据中
Posted
技术标签:
【中文标题】使用 Python 将 sigmoid 函数(“S”形曲线)拟合到数据中【英文标题】:Fit sigmoid function ("S" shape curve) to data using Python 【发布时间】:2019-09-07 13:23:37 【问题描述】:我正在尝试为我拥有的一些数据拟合 sigmoid 函数,但我不断得到:ValueError: Unable to determine number of fit parameters.
我的数据如下所示:
我的代码是:
from scipy.optimize import curve_fit
def sigmoid(x):
return (1/(1+np.exp(-x)))
popt, pcov = curve_fit(sigmoid, xdata, ydata, method='dogbox')
然后我得到:
---------------------------------------------------------------------------
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.
我不确定为什么这不起作用,这似乎是一个微不足道的动作--> 将曲线拟合到某个点。所需的曲线如下所示:
抱歉,我用 PowerPoint 做的...
如何找到最佳的 sigmoid(“S”形)曲线?
更新
感谢@Brenlla,我已将代码更改为:
def sigmoid(k,x,x0):
return (1 / (1 + np.exp(-k*(x-x0))))
popt, pcov = curve_fit(sigmoid, xdata, ydata, method='dogbox')
现在我没有收到错误,但曲线不符合预期:
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')
结果是:
我怎样才能改进它以更好地适应数据?
更新2
现在的代码是:
def sigmoid(x, L,x0, k, b):
y = L / (1 + np.exp(-k*(x-x0)))+b
但是结果还是……
【问题讨论】:
您想使用 logistic function,而不是纯 sigmoidal。使用x0
、k
和L
作为要优化的参数
谢谢@Brenlla,你能帮我更新一下吗?
添加一个额外的参数 1 / (1 + np.exp(-k*(x-x0)))+b
因为您的积分不是从 0 开始(更像是 0.3)
你必须提供合理的p0
作为起点,例如here
@Brenlla 这非常有帮助!谢谢你的解决方案。不过,我有一个小问题——在拟合 Logistic 曲线之前,您是如何选择如此好的初始估计值的?是否有一些资源可以指导我,以便我也可以找到对数和幂曲线的良好初始估计值?
【参考方案1】:
在@Brenlla 的大力帮助下,代码修改为:
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')
优化的参数为L, x0, k, b
,初始赋值在p0
,优化的起始点。
L
负责将输出范围从[0,1]缩放到[0,L]
b
为输出添加偏差并将其范围从 [0,L] 更改为 [b,L+b]
k
负责缩放输入,保留在 (-inf,inf) 中
x0
是 Sigmoid 中间的点,即 Sigmoid 最初应该输出值的点 1/2
[因为如果 x=x0,我们得到 1/(1+exp(0)) = 1/2] .
结果:
【讨论】:
对于我的数据,选择接近解决方案的初始猜测是不够的。我还必须添加一些界限:curve_fit(sigmoid, xdata, ydata,p0, bounds=(min_vals,max_vals), method='dogbox') 简要说明参数 L、k 和 b 可能对到达这里的其他人有所帮助。 谢谢!这个答案对我有帮助。就像补充一点,改变 k 的初始值帮助我更好地适应我的数据 你是一个救生员。这很有帮助,尤其是对 p0 的初步猜测。 将L
的初始猜测设置为max(ydata)-min(ydata)
,而不是仅仅max(ydata)
不是更好吗?【参考方案2】:
注意 - 之前有一些关于初步估算的问题。我的数据特别混乱,上面的解决方案大部分都有效,但偶尔会完全错过。通过将方法从 'dogbox'
更改为 'lm'
来解决这个问题:
p0 = [max(ydata), np.median(xdata),1,min(ydata)] # this is an mandatory initial guess
popt, pcov = curve_fit(sigmoid, xdata, ydata,p0, method='lm') ## Updated method from 'dogbox' to 'lm' 9.30.2021
大约 50 多条拟合曲线,它根本没有改变运行良好的曲线,而是完全解决了挑战案例。
重点是,在任何情况下,您和您的数据都是一片特殊的雪花,所以不要害怕深入研究您从互联网复制的函数的参数。
【讨论】:
以上是关于使用 Python 将 sigmoid 函数(“S”形曲线)拟合到数据中的主要内容,如果未能解决你的问题,请参考以下文章