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

时间:2016-10-14 15:33:29

标签: python numpy optimization scipy linear-algebra

我想知道将数据点拟合到非线性函数的正确方法应该是在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)

我知道这是不成功的,因为我能够解决"等同于"线性最小二乘问题(简单地通过获取模型函数的对数得到)并且它的答案甚至不会接近我通过上述方法得到的那个。

谢谢

3 个答案:

答案 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), '-')

Example

答案 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可用于拟合数据。我认为你没有正确使用它。我假设您有一个给定的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。