我有一些遵循sigmoid分布的数据,如下图所示:
在对数据进行标准化和缩放后,我使用scipy.optimize.curve_fit
和一些初始参数调整了底部的曲线:
popt, pcov = curve_fit(sigmoid_function, xdata, ydata, p0 = [0.05, 0.05, 0.05])
>>> print popt
[ 2.82019932e+02 -1.90996563e-01 5.00000000e-02]
所以popt
,根据the documentation,返回*“参数的最佳值,以便f(xdata, popt) - ydata的平方误差之和最小化”< / em>的。我在这里理解,没有用curve_fit
计算斜率,因为我不认为这条平缓曲线的斜率是282,也不是负数。
然后我尝试使用scipy.optimize.leastsq
,因为文档说它返回“解决方案(或不成功调用的最后一次迭代的结果)。”,所以我认为斜率将被退回。像这样:
p, cov, infodict, mesg, ier = leastsq(residuals, p_guess, args = (nxdata, nydata), full_output=True)
>>> print p
Param(x0=281.73193626250207, y0=-0.012731420027056234, c=1.0069006606656596, k=0.18836680131910222)
但同样,我没有得到我的预期。 curve_fit
和leastsq
返回了几乎相同的值,我猜这并不奇怪,因为curve_fit
正在使用最小二乘法的实现来查找曲线。但没有斜坡......除非我忽略了什么。
那么,如何计算一个点的斜率,比如,X = 285和Y = 0.5?
我试图避免手动方法,例如calculating the derivative,例如,(285.5,0.55)和(284.5,0.45),并减去并除以结果等等。我想知道是否有更自动的方法。
谢谢大家!
编辑#1
这是我的“sigmoid_function”,由curve_fit和leastsq方法使用:
def sigmoid_function(xdata, x0, k, p0): # p0 not used anymore, only its components (x0, k)
# This function is called by two different methods: curve_fit and leastsq,
# this last one through function "residuals". I don't know if it makes sense
# to use a single function for two (somewhat similar) methods, but there
# it goes.
# p0:
# + Is the initial parameter for scipy.optimize.curve_fit.
# + For residuals calculation is left empty
# + It is initialized to [0.05, 0.05, 0.05]
# x0:
# + Is the convergence parameter in X-axis and also the shift
# + It starts with 0.05 and ends up being around ~282 (days in a year)
# k:
# + Set up either by curve_fit or leastsq
# + In least squares it is initially fixed at 0.5 and in curve_fit
# + to 0.05. Why? Just did this approach in two different ways and
# + it seems it is working.
# + But honestly, I have no clue on what it represents
# xdata:
# + Positions in X-axis. In this case from 240 to 365
# Finally I changed those parameters as suggested in the answer.
# Sigmoid curve has 2 degrees of freedom, therefore, the initial
# guess only needs to be this size. In this case, p0 = [282, 0.5]
y = np.exp(-k*(xdata-x0)) / (1 + np.exp(-k*(xdata-x0)))
return y
def residuals(p_guess, xdata, ydata):
# For the residuals calculation, there is no need of setting up the initial parameters
# After fixing the initial guess and sigmoid_function header, remove []
# return ydata - sigmoid_function(xdata, p_guess[0], p_guess[1], [])
return ydata - sigmoid_function(xdata, p_guess[0], p_guess[1], [])
如果我在描述参数或混淆技术术语时犯了错误,我很抱歉。我很笨,我多年没学过数学,所以我又回来了。
那么,再次,您对计算此数据集的X = 285,Y = 0.5(或多或少中间点)的斜率有何建议?谢谢!!
编辑#2
感谢Oliver W.,我按照他的建议更新了我的代码并理解了问题。
我还没有完全掌握最后的细节。显然,curve_fit
返回一个popt
数组(x0,k),其中包含拟合的最佳参数:
x0
似乎是通过指示曲线的中心点来改变曲线k
参数是y = 0.5时的斜率,也是曲线的中心(我想!)为什么如果sigmoid函数是一个增长函数,popt中的导数/斜率是负的?它有意义吗?
我使用sigmoid_derivative
来计算斜率,是的,我获得的结果与popt
相同,但带有正号。
# Year 2003, 2005, 2007. Slope in midpoint.
k = [-0.1910, -0.2545, -0.2259] # Values coming from popt
slope = [0.1910, 0.2545, 0.2259] # Values coming from sigmoid_derivative function
我知道这有点高峰,因为我可以同时使用它们。相关数据在那里,但有负号,但我想知道为什么会发生这种情况。
因此,只有当我需要知道除y = 0.5 之外的其他点的斜率时,才需要按照您的建议计算导数函数。仅限中点,我可以使用popt
。
感谢您的帮助,这为我节省了很多时间。 : - )
答案 0 :(得分:2)
你永远不会使用你传递给sigmoid函数的参数p0
。因此,曲线拟合不具有找到收敛的任何好的量度,因为它可以取该参数的任何值。你应该首先重写你的sigmoid函数:
def sigmoid_function(xdata, x0, k):
y = np.exp(-k*(xdata-x0)) / (1 + np.exp(-k*(xdata-x0)))
return y
这意味着你的模型(sigmoid)只有两个自由度。这将在popt
:
initial_guess = [282, 1] # (x0, k): at x0, the sigmoid reaches 50%, k is slope related
popt, pcov = curve_fit(sigmoid_function, xdata, ydata, p0=initial_guess)
现在popt
将是一个元组(或2个值的数组),是最好的x0
和k
。
为了在任何一点得到这个函数的斜率,说实话,我只是象征性地计算导数,因为sigmoid不是那么难的函数。你最终会得到:
def sigmoid_derivative(x, x0, k):
f = np.exp(-k*(x-x0))
return -k / f
如果曲线拟合的结果存储在popt
中,您可以轻松地将其传递给此函数:
print(sigmoid_derivative(285, *popt))
将返回x=285
的衍生物。但是,因为你专门询问中点,所以当x==x0
和y==.5
时,你会看到(来自sigmoid_derivative)导数只有-k
,可以立即观察到来自您已经获得的curve_fit
输出。在您显示的输出中,大约是0.19。