我想知道将数据点拟合到非线性函数的正确方法应该是在python中。
我正在尝试拟合一系列数据点
t = [0., 0.5, 1., 1.5, ...., 4.]
y = [6.3, 4.5,.................]
使用以下模型函数
f(t, x) = x1*e^(x2*t)
我主要想知道哪个库例程适合这个问题以及如何设置它。我尝试使用以下不成功的结果:
t_data = np.array([0.5, 1.0, 1.5, 2.0,........])
y_data = np.array([6.8, 3., 1.5, 0.75........])
def func_nl_lsq(x, t, y):
return [x[0]*np.exp(x[1]*t)] - y
popt, pcov = scipy.optimize.curve_fit(func_nl_lsq, t_data, y_data)
我知道这是不成功的,因为我能够解决"等同于"线性最小二乘问题(简单地通过获取模型函数的对数得到)并且它的答案甚至不会接近我通过上述方法得到的那个。
谢谢
答案 0 :(得分:3)
如果您使用的是curve_fit
,可以将其简化一点,无需计算函数内的错误:
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
t_data = np.array([0.5, 1.0, 1.5, 2.0, 2.5, 3.])
y_data = np.array([6.8, 3., 1.5, 0.75, 0.25, 0.1])
def func_nl_lsq(t, *args):
a, b = args
return a*np.exp(b*t)
popt, pcov = curve_fit(func_nl_lsq, t_data, y_data, p0=[1, 1])
plt.plot(t_data, y_data, 'o')
plt.plot(t_data, func_nl_lsq(t_data, *popt), '-')
plt.show()
注意我使用的是接受*args
的常规签名。为了实现此目的,您必须将p0
传递给curve_fit
。
传统方法如下所示:
def func_nl_lsq(t, a, b):
return a*np.exp(b*t)
popt, pcov = curve_fit(func_nl_lsq, t_data, y_data)
a, b = popt
plt.plot(t_data, func_nl_lsq(t_data, a, b), '-')
答案 1 :(得分:1)
首先,您使用的是错误的功能。您的函数func_nl_lsq
计算残差,而不是模型函数。要使用scipy.otimize.curve_fit
,您必须定义模型函数,作为@DerWeh和@saullo_castro建议的答案。您仍然可以使用scipy.optimize.least_squares
代替scipy.optimize.curve_fit
来使用自定义残差函数。
t_data = np.array([0.5, 1.0, 1.5, 2.0])
y_data = np.array([6.8, 3., 1.5, 0.75])
def func_nl_lsq(x, t=t_data, y=y_data):
return x[0]*np.exp(x[1]*t) - y
# removed one level of []'s
scipy.optimize.least_squares(func_nl_lsq, [0, 0])
另外,请注意,@MadPhysicist的注释是正确的:您正在考虑的两个问题(初始问题和模型函数在对数下的问题)并不相同。请注意,如果将对数应用于模型函数,则也将其应用于残差,而残差平方和现在意味着不同的东西。这导致了不同的优化问题和不同的结果。
答案 2 :(得分:0)
scipy.otimize.curve_fit
可用于拟合数据。我认为你没有正确使用它。我假设您有一个给定的t
和y
,并尝试使用x1*exp(x2*t) = y
形式的函数。
你需要
ydata = f(xdata, *params) + eps
这意味着您的功能未正确定义。你的功能应该看起来像
def func_nl_lsq(t, x1, x2):
return x1*np.exp(x2*t)
取决于你真正想要的东西。这里x1和x2是你的拟合参数。也可以这样做
def func_nl_lsq(t, x):
return x[0]*np.exp(x[1]*t)
但您可能需要提供初步猜测p0。