繁体   English   中英

Scipy的curve_fit没有给出合理的结果

[英]Scipy's curve_fit not giving reasonable result

我有一个简单的x,y数据集,至少乍一看。 问题是scipy.optimize.curve_fit为其中一个参数提供了一个非常大的值,我不知道这是否在数学上是正确的,或者我是如何拟合数据的。

下图显示了以蓝色获得的数据点和最佳拟合。 使用的曲线(下面的MWE中的func )有四个参数a, b, c, d拟合:

  • a给出近似x值,曲线达到它的半最大值。
  • b表示曲线稳定x值。 func值由d参数给出,即: func(b) = d
  • c与原点处曲线的最大值有关: func(0) = c*constant + d
  • d是曲线稳定的地方(图中的黑线)。

b参数是我遇到的问题(参见问题的结尾),它也是我感兴趣的分配合理值的参数。

在此输入图像描述

MWE显示正在拟合的功能和结果:

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

# Function to be fitted.
def func(x, a, b, c, d):
    return c * (1 / np.sqrt(1 + (np.asarray(x) / a) ** 2) -
        1 / np.sqrt(1 + (b / a) ** 2)) ** 2 + d

# Define x,y data.    
x_list = [12.5, 37.5, 62.5, 87.5, 112.5, 137.5, 162.5, 187.5, 212.5, 237.5,
    262.5, 287.5, 312.5, 337.5, 362.5, 387.5, 412.5, 437.5, 462.5, 487.5,
    512.5]
y_list = [0.008, 0.0048, 0.0032, 0.00327, 0.0023, 0.00212, 0.00187,
    0.00086, 0.00070, 0.00100, 0.00056, 0.00076, 0.00052, 0.00077, 0.00067,
    0.00048, 0.00078, 0.00067, 0.00069, 0.00061, 0.00047]

# Initial guess for the 4 parameters.
guess = (50., 200., 80. / 10000., 6. / 10000.)

# Fit curve to x,y data.
f_prof, f_err = curve_fit(func, x_list, y_list, guess)

# Values for the a,b,c,d fitted parameters.
print f_prof

# Errors (standard deviations) for the fitted parameters.
print np.sqrt(f_err[0][0]), np.sqrt(f_err[1][1]), np.sqrt(f_err[2][2]),\
    np.sqrt(f_err[3][3])

# Generate plot.
plt.scatter(x_list, y_list)
plt.plot(x_list, func(x_list, f_prof[0], f_prof[1], f_prof[2], f_prof[3]))
plt.hlines(y=f_prof[3], xmin=0., xmax=max(x_list))
plt.show()

我得到的结果是:

# a, b, c, d
 52.74, 2.52e+09, 7.46e-03, 5.69e-04

# errors
11.52, 1.53e+16, 0.0028, 0.00042

b参数具有巨大的值,也是一个巨大的错误。 通过查看图中绘制的数据,可以通过眼睛估计b的值(即:数据集稳定x值)应该在x=300 为什么我为b及其错误获得如此大的值?

你可以使用惩罚值作为参数的范数,并使用fmin

from scipy.optimize import fmin

def func(x, a, b, c, d):
    return c * (1 / np.sqrt(1 + (x / a) ** 2) - 1 / np.sqrt(1 + (b / a) ** 2)) ** 2 + d

def errfn(params, xs, ys, lm, ord=1):
    '''
    lm: penalty maltiplier
    ord: order in norm calculation
    '''
    from numpy.linalg import norm
    a, b, c, d = params
    err = func(xs, a, b, c, d) - ys
    return norm(err) + lm * norm(params, ord)

params = fmin(errfn, guess, args=(xs, ys, 1e-6, 2))

上面我使用1e-6的小罚款,合适的结果是

[6.257e+01   3.956e+02   9.926e-03   7.550e-04]

身体健康:

适合

编辑 :玩惩罚函数和规范顺序,它非常适合

params = [  1.479e+01  -3.344e+00  -8.781e-03   8.347e-03]

FIT2

我不知道这是故意的还是错误的,但在我看来,'b'将与'a'和'd'强烈相关,并且与自变量'x'没有“相互作用”。 如果b / a足够大,你可以将1 / np.sqrt(1 +(b / a)** 2))** 2近似为a / b,这样你的函数就变成c * function_of(x,a) - a / b + d

你的'a'和'x'值足够大,几乎变成了c * a / x - a / b + d。

正如behzad.nouri所指出的,与其他最小化器相比,curve_fit可能稍微不稳定,并且总是最小化最小二乘。 但它确实返回完整的协方差矩阵,包括变量之间的相关性(f_err的非对角线元素)。 用这些!!

如果您确定'b'的值大约为300,或者有兴趣在fmin和levenberg-marquardt算法之间轻松切换,您可能会找到lmfit包( http://lmfit.github.io/lmfit-py/ )有用。 它允许您在参数上设置界限,在拟合算法之间轻松切换,还可以对参数的置信区间进行更强力的探索。

从快速看,似乎大b将消除func()的第二项:

b/a变为无穷大时, 1 / np.sqrt(1 + (b / a) ** 2)) ** 2变为零。

这告诉我,模型中不需要这部分功能,并且造成的伤害大于好处。

只需将func设置为:

c * (1 / np.sqrt(1 + (np.asarray(x) / a) ** 2) + d

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM