Python中的非线性曲线拟合程序

3
我想找到并绘制一个函数f,该函数表示已知一些集合点x和y上拟合的曲线。经过一些研究,我开始尝试使用scipy.optimize和curve_fit进行实验,但在参考指南中我发现该程序使用一个函数来适应数据,并且假设ydata = f(xdata,* params)+ eps。
所以我的问题是:我需要在代码中更改什么才能使用curve_fit或任何其他库来查找使用我的设置点的曲线函数?(注意:我也想知道该函数,以便稍后在我的项目中进行积分和绘制)。我知道它将是一个衰减指数函数,但不知道确切的参数。这是我在程序中尝试的内容:
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit

    def func(x, a, b, c):
        return a * np.exp(-b * x) + c

    xdata = np.array([0.2, 0.5, 0.8, 1])
    ydata = np.array([6, 1, 0.5, 0.2])
    plt.plot(xdata, ydata, 'b-', label='data')
    popt, pcov = curve_fit(func, xdata, ydata)
    plt.plot(xdata, func(xdata, *popt), 'r-', label='fit')

    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()
    plt.show()

目前正在树莓派上开发此项目,如果有变化,请告知。我希望使用最小二乘法,因为它很好并且精确,但是欢迎任何其他有效的方法。

同样,这是基于scipy库的参考指南。 我得到了以下图形,这甚至不是一条曲线:基于设定点的图形和曲线

[1]


2
除了绘图之外,一切都很好:“x = np.arange(0, 1, 0.01)”然后“plt.plot(x, func(x, *popt), 'r-', label='fit')”,因为您想要在更多点上评估拟合函数,以获得平滑的结果。关于拟合参数,它们在popt数组中。 - Mauro Lacy
1
你现有的代码存在什么问题?编辑:@MauroLacy确认了我的猜测。 - AGN Gazer
1个回答

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

def func(x, a, b, c):
    return a * np.exp(-b * x) + c

#c is a constant so taking the derivative makes it go to zero
def deriv(x, a, b, c):
    return -a * b * np.exp(-b * x)

#Integrating gives you another c coefficient (offset) let's call it c1 and set it equal to zero by default
def integ(x, a, b, c, c1 = 0):
    return -a/b * np.exp(-b * x) + c*x + c1

#There are only 4 (x,y) points here
xdata = np.array([0.2, 0.5, 0.8, 1])
ydata = np.array([6, 1, 0.5, 0.2])

#curve_fit already uses "non-linear least squares to fit a function, f, to data"
popt, pcov = curve_fit(func, xdata, ydata)
a,b,c = popt #these are the optimal parameters for fitting your 4 data points

#Now get more x values to plot the curve along so it looks like a curve
step = 0.01
fit_xs = np.arange(min(xdata),max(xdata),step)

#Plot the results
plt.plot(xdata, ydata, 'bx', label='data')
plt.plot(fit_xs, func(fit_xs,a,b,c), 'r-', label='fit')
plt.plot(fit_xs, deriv(fit_xs,a,b,c), 'g-', label='deriv')
plt.plot(fit_xs, integ(fit_xs,a,b,c), 'm-', label='integ')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()

deriv and integ


1
你应该将数据显示为点,类似于“bx”,而不是曲线(虽然这是一个相当普遍的评论,不必太在意)。 - jadsq
我喜欢这个建议,我认为它使曲线拟合点更加清晰。 - mitoRibo
嗯,这很有道理,我需要更好地拟合曲线的步骤。那么,只是为了明确,func会给我曲线的方程吗?如果是这样,那么以后我可以用积分、导数等方式来操作函数“func”吗? - fdev
curve_fit 的返回值将是曲线 A、B、C 的系数,在这种情况下为 Aexp(-BX)+C。如果你想要进行积分和导数,我建议你先在纸上完成,然后再创建一个新的函数。在这种情况下,导数为 -AB*exp(-BX),因此你可以创建另一个函数来绘制它。积分也是同样的思路。 - mitoRibo
如果curve_fit()没有传递“p0”初始参数,scipy将使用所有1.0的默认参数。对于更复杂的方程,这可能是次优的,因此scipy的作者添加了微分进化遗传算法来进行初始参数估计。该模块名为scipy.optimize.differential_evolution,并且它使用拉丁超立方体算法来确保对参数空间进行彻底搜索。我已经使用它来将双洛伦兹方程拟合到碳纳米管的拉曼光谱数据中,并取得了出色的结果,网址为https://bitbucket.org/zunzuncode/RamanSpectroscopyFit。 - James Phillips

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接