numpy Python中的非线性最小二乘拟合(二维)

camsedfj  于 12个月前  发布在  Python
关注(0)|答案(3)|浏览(174)

我想知道在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)


我知道这是不成功的,因为我能够解决“等效”线性最小二乘问题(简单地通过取模型函数的对数获得),它的答案甚至不接近我通过上面的方法得到的答案。
谢谢你

8yoxcaq7

8yoxcaq71#

如果你使用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), '-')


的数据

2wnc66cl

2wnc66cl2#

首先,你使用了错误的函数。你的函数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的评论是正确的:你正在考虑的两个问题(初始问题和模型函数为对数的问题)并不等价。请注意,如果您将对数应用于模型函数,则也将其应用于残差,并且 * 残差平方和 * 现在意味着不同的东西。这会导致不同的优化问题和不同的结果。

ergxz8rk

ergxz8rk3#

scipy.otimize.curve_fit可以用来拟合数据。我认为你只是没有正确使用它。我假设你有一个给定的ty,并试图拟合一个形式为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。

相关问题