如下面的图像所示,我有一些数据呈S型分布:
在对数据进行归一化和缩放后,我使用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]
因此,根据the documentation的
popt
返回*“参数的最佳值,以使f(xdata,popt)-ydata的平方误差之和最小”。我在这里了解到,没有使用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?
我试图避免手动方法,例如(285.5,0.55)和(284.5,0.45)中的calculating the derivative,然后减去和除以结果。我想知道是否有更自动的方法。
谢谢你们!
编辑#1
这是我的“ sigmoid_function”,由curve_fit和minimumsq方法使用:
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], [])
如果在描述参数或混淆技术术语时出错,我们感到抱歉。我对numpy很陌生,而且我已经好多年没有学习数学了,所以我又迎头赶上了。
那么,对于此数据集,您如何建议计算X = 285,Y = 0.5(或多或少的中点)的斜率呢?谢谢!!
编辑#2
感谢Oliver W.,我按照他的建议更新了代码,并更好地理解了这个问题。
我还没有完全了解最后一个细节。显然,
curve_fit
返回具有最佳拟合参数的popt
数组(x0,k):x0
似乎是通过指示曲线的中心点来改变曲线的方向k
参数是y = 0.5时的斜率,也位于曲线的中心(我认为!)如果S型函数是一个增长的函数,为什么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
。感谢您的帮助,它节省了我很多时间。 :-)
最佳答案
您永远不会使用传递给Sigmoid函数的参数p0
。因此,曲线拟合将没有任何好的方法来找到收敛性,因为它可以为该参数取任何值。您首先应该像这样重写Sigmoid函数:
def sigmoid_function(xdata, x0, k):
y = np.exp(-k*(xdata-x0)) / (1 + np.exp(-k*(xdata-x0)))
return y
这意味着您的模型(S型)只有两个自由度。这将在
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
。老实说,要在任何时候获得该函数的斜率,我只能象征性地计算导数,因为S形不是这样的硬函数。您最终将得到:
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。关于python - SciPy + Numpy:找到S形曲线的斜率,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26607237/