Python中Sigmoid函数的曲线拟合与外推

7kqas0il  于 2023-03-24  发布在  Python
关注(0)|答案(2)|浏览(253)

我有下面的数据集:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

## Given datapoints
xdata = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26])
ydata = np.array([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.99330715, 0.98201379, 0.95257413, 0.88079708, 0.73105858, 0.5])

## Plot the data
plt.plot(xdata, ydata)
plt.xlabel('x')
plt.ylabel('sigmoid(x)')
plt.xlim([-1,31])
plt.ylim(0, 1.05)
plt.show()

上面的数据看起来是这样的:

需要使用python中的curve_fit对曲线进行校准和外推,以使y从1减小到0。
我试图使用sigmoid函数提供'y'是给定的,'x'需要找到。

因此,拟合'x'的sigmoid函数定义如下:

## Define sigmoid function to fit xdata
def sigmoid(y, x0, k):
    x = x0 + ((1/k)*(np.log((1/y)-1)))
    return x

## Initial guess
p0 = [np.median(xdata),       # x0
      0.1]                    # k

## Initialize curve fit
popt, pcov = curve_fit(sigmoid,
                       ydata,
                       xdata)

## Define values for y
y = np.arange(1,0,-0.001)

## Evaluate values for x
x = sigmoid(y, *popt)

## Plot tbe actual and fit data
plt.plot(xdata, ydata, 'o', label='data')
plt.plot(x,y, label='fit')
plt.xlim([-10,31])
plt.ylim(0, 1.05)
plt.legend(loc='best')
plt.show()

拟合数据如下所示:

很明显,合身度不好。
有人能告诉我如何拟合出接近实际数据的曲线吗?

xuo3flqw

xuo3flqw1#

问题是在要拟合的方程中有ln((1/y)-1),当y=1时,ln((1/y)-1)是无穷大的,y=1的点不必考虑,这样拟合就很好:

当y趋于1(但小于1)时,则x趋于-无穷大,这与数据和曲线的形状一致。

guicsvcw

guicsvcw2#

您可能会发现lmfit对此很有用(免责声明:我是第一作者),因为它内置了S形阶跃函数,可以很容易地进行拟合,并使用这些结果来插值或外推。它还提供了比curve_fit更有用的结果报告,变量参数具有有意义的名称和不确定性以及正确计算,排序和分配的相关性。
您的示例可能如下所示:

import numpy as np
import matplotlib.pyplot as plt

from lmfit.models import StepModel, ConstantModel

#
xdata = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26])
ydata = np.array([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.99330715, 0.98201379, 0.95257413, 0.88079708, 0.73105858, 0.5])

# create a logistic step function + an offset constant
model = StepModel(form='logistic') + ConstantModel()

# make a set of parameters with initial values
params = model.make_params(c=1, amplitude=-1, center=25, sigma=2.5)

# fit the data with the parameters and `x` independent variable
result = model.fit(ydata, params, x=xdata)

# print results
print(result.fit_report())

# evaluate the model with best-fit parameters to 
# interpolate and extrapolate to higher x values
xnew = np.linspace(15, 45, 121)
ynew = model.eval(result.params, x=xnew)

## Plot the data, best-fit result, and extrapolated data
plt.plot(xdata, ydata, 'o', label='data')
plt.plot(xdata, result.best_fit, '-', label='best fit')
plt.plot(xnew,  ynew, '+', label='exptrapolated')
plt.xlabel('x')
plt.ylabel('sigmoid(x)')
plt.xlim([-1,41])
plt.ylim(0, 1.05)
plt.legend()
plt.show()

它会打印一份报告

[[Model]]
    (Model(step, form='logistic') + Model(constant))
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 82
    # data points      = 27
    # variables        = 4
    chi-square         = 6.4177e-06
    reduced chi-square = 2.7903e-07
    Akaike info crit   = -403.811763
    Bayesian info crit = -398.628416
    R-squared          = 0.99997896
[[Variables]]
    amplitude: -0.99669011 +/- 0.01320863 (1.33%) (init = -1)
    center:     25.9928183 +/- 0.02578216 (0.10%) (init = 25)
    sigma:      0.99867632 +/- 0.00629747 (0.63%) (init = 2.5)
    c:          1.00015992 +/- 1.1486e-04 (0.01%) (init = 1)
[[Correlations]] (unreported correlations are < 0.100)
    C(amplitude, center) = -0.997
    C(center, sigma)     = 0.954
    C(amplitude, sigma)  = -0.943
    C(sigma, c)          = 0.287
    C(amplitude, c)      = -0.223

画一个这样的图

相关问题