如下面的图像所示,我有一些数据呈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 documentationpopt返回*“参数的最佳值,以使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_fitleastsq返回几乎相同的值,我猜不足为奇,因为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个值的数组),它们是最好的x0k

老实说,要在任何时候获得该函数的斜率,我只能象征性地计算导数,因为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==x0y==.5时,(从sigmoid_derivative中)您会看到导数只是-k,可以从curve_fit输出中立即观察到您已经获得了。在显示的输出中,大约为0.19。

关于python - SciPy + Numpy:找到S形曲线的斜率,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26607237/

10-12 17:56