【问题标题】:Scipy Curve_fit: Why is my fitting so poor and how to improve it?Scipy Curve_fit:为什么我的拟合这么差,如何改进?
【发布时间】:2019-06-05 16:30:53
【问题描述】:

我正在尝试使用 python 的 curve_fit 库来拟合我的数据。虽然我可以捕捉到数据的模式,但真正的契合度相当差。有什么方法可以提高合身的质量吗?

这是我的代码:

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

x=np.array([ 4.29977288,  4.18759576,  3.937875  ,  3.68784896,  3.43711213,
    3.19099287,  2.94166468,  2.68543877,  2.4289324 ,  2.19035861,
    1.93962193,  1.69285434,  1.44271633,  1.18869615,  0.94761142,
    0.69828307,  0.44606364,  0.19355101, -0.05367106, -0.30303661,
   -0.55272018, -0.79877747, -1.04806864, -1.29706657, -1.54567223,
   -1.79685098, -2.05011095, -2.29874144, -2.54813208, -2.80178461,
   -3.04828379, -3.29893363, -3.54727073, -3.79908534, -4.04661293]);

y=np.array([ 20.8744534 ,  20.89824536,  20.3763843 ,  19.79924837,
    19.19485964,  18.57716717,  17.93772371,  17.28834168,
    16.62367817,  15.94336213,  15.24389099,  14.52471466,
    13.7787734 ,  13.00299723,  12.18721413,  11.31510566,
    10.36672642,   9.32224105,   8.14237084,   6.78034367,
     5.19700447,   3.32945537,   1.10437136,  -1.48805508,
    -4.25695201,  -6.94906329,  -9.41648974, -11.54747381,
   -13.33444597, -14.90663076, -16.36783375, -17.72241553,
   -18.9592222 , -20.06703821, -21.07669491])

def func(x,A,B,C):
    a=1+B/A
    b=1-B/A
    k=C/np.log(a/b)
    y=A*np.tanh((x-C)/(2*k))
    return y

A_0=25
B_0=10
C_0=1.2


popt,pcov = curve_fit(func,x,y,p0=[A_0,B_0,C_0])
print(pcov)

plt.plot(x,y,label='Data')
plt.plot(x,func(x, *popt),'.',label='Fit')
plt.legend()
plt.show()

【问题讨论】:

  • 如果以下任何答案解决了您的问题,请将您认为最好的答案标记为已接受

标签: python scipy curve-fitting


【解决方案1】:

这不是curve_fit 的问题,而是您正在使用的功能的问题。找到一个可以完成这项工作的函数并不总是那么容易,但是例如一个错误函数会做得更好:

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

x=np.array([ 4.29977288,  4.18759576,  3.937875  ,  3.68784896,  3.43711213,
    3.19099287,  2.94166468,  2.68543877,  2.4289324 ,  2.19035861,
    1.93962193,  1.69285434,  1.44271633,  1.18869615,  0.94761142,
    0.69828307,  0.44606364,  0.19355101, -0.05367106, -0.30303661,
   -0.55272018, -0.79877747, -1.04806864, -1.29706657, -1.54567223,
   -1.79685098, -2.05011095, -2.29874144, -2.54813208, -2.80178461,
   -3.04828379, -3.29893363, -3.54727073, -3.79908534, -4.04661293]);

y=np.array([ 20.8744534 ,  20.89824536,  20.3763843 ,  19.79924837,
    19.19485964,  18.57716717,  17.93772371,  17.28834168,
    16.62367817,  15.94336213,  15.24389099,  14.52471466,
    13.7787734 ,  13.00299723,  12.18721413,  11.31510566,
    10.36672642,   9.32224105,   8.14237084,   6.78034367,
     5.19700447,   3.32945537,   1.10437136,  -1.48805508,
    -4.25695201,  -6.94906329,  -9.41648974, -11.54747381,
   -13.33444597, -14.90663076, -16.36783375, -17.72241553,
   -18.9592222 , -20.06703821, -21.07669491])

def func(x,A,B,C):
    a=1+B/A
    b=1-B/A
    k=C/np.log(a/b)
    y=A*np.tanh((x-C)/(2*k))
    return y

def erf(x, a, b, c, d):
    return d + 0.5*c*(1 + special.erf(a*(x-b)))

A_0=25
B_0=10
C_0=1.2


popt,pcov = curve_fit(func,x,y,p0=[A_0,B_0,C_0])
perf, pecov = curve_fit(erf, x, y, p0=(0.5,0,40,-20))

plt.plot(x,y, 'o', label='Data')
plt.plot(x,func(x, *popt),'-',label='Fit')
plt.plot(x, erf(x, *perf), '--', label='erf fit')
plt.legend()
plt.show()

【讨论】:

  • 出色的工作,所以我投了赞成票。有关数据形状的其他评论,请参阅我对此问题的回答。
【解决方案2】:

我不确定你是否一定要使用你正在使用的函数,或者你也可以使用多项式。在后一种情况下,您可以使用polyfit。

请记住,您不能只使用任何高阶多项式,否则您最终会过度拟合数据。您可以查看拟合的均方根误差,以衡量其准确性

fit = np.poly1d(np.polyfit(x, y, 5))

plt.plot(x, y, '.', label='Data')
plt.plot(x, fit(x), label='Fit')
plt.legend()

【讨论】:

  • 很合适,我注意到你的情节中的一些东西,我在进行方程搜索时也发现了:情节上最左边的点有曲线上升到最左边的数据点之上。如果需要,在回归中给这个点额外的权重可以减少这个端点曲率。
  • @JamesPhillips :是的,您可以创建一个约 -21 的多项式。在 x=-4.1 以强制曲线从第一个点开始而不是上升。我不完全确定如何,但只是一些想法
【解决方案3】:

我认为 Sigmoid 或峰值方程可能会对数据进行建模,以下是峰值方程和建模误差的示例图:

就好像有两个组合信号,其中一个是低幅度循环信号。第二个信号不是简单的正弦波。我的想法是,您可能需要一个复杂的模型,该模型是两个不同方程的总和,以便在单个模型中捕获这两个组件。

【讨论】:

    猜你喜欢
    • 2016-11-29
    • 2012-11-02
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 2022-07-29
    相关资源
    最近更新 更多