用指数定律拟合数据

问题描述

我想用指数函数拟合一些数据。我使用 scipy.optimize.curve_fit 是因为我已经将它用于其他拟合。这一次,出现了一个问题,我无法弄清楚出了什么问题。

这是绘制时数据的样子: data.png

如您所见,它似乎遵循指数规律。

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

data = np.array([ 
    0.,1.93468444,3.69735865,5.38185988,6.02549022,6.69199075,7.72316694,8.08913061,8.84570241,8.69711608,8.80038144,9.78951087,9.68486674,10.06175145,10.44039495,10.0481156,9.76656204,9.88581457,9.81805445,10.42432252,10.41102239,11.2911395,9.64866184,9.98072231,10.83644694,10.24748571,10.81333209,10.75949899,10.90367328,10.42446764,10.51441017,10.73047737,10.8159758,10.51013538,10.02862504,9.76352112,10.64829309,10.6293347,10.67752596,10.34801542,10.53158576,10.92883362,10.67002314,10.37015825,10.74876349,10.12821343,10.8974205,10.1591103,10.588377,11.92134556,10.309095,11.1174362,10.72654524,10.60890374,10.37456491,10.05935346,11.21295863,11.09013951,10.60862773,11.2558922,11.24660234,10.35981557,10.81284365,10.96113067,10.22716439,9.8394873,10.01892084,10.38237311,10.04920671,10.87782442,10.42438756,10.05614503,10.5446946,9.99974368,10.76930547,10.22164072,10.36942999,10.89888302,10.47035428,10.58157374,11.12615892,11.30866718,10.33215937,10.46723351,10.54072701,11.45027197,10.45895588,10.34176601,10.78405493,10.43964778,10.34047484,10.25099046,11.05847515,10.27408195,10.27529163,10.16568845,10.86451738,10.73205291,10.73300649,10.49463959,10.03729782
])

t = np.linspace(0,100,len(data)) #time array

def expo(x,a,b,c): #exponential function for fitting
   return a * np.exp(b * x) + c

fig1,ax1 = plt.subplots()
ax1.plot(t,data,".",label="data")
coefs = curve_fit(expo,t,data)[0] # fitting
ax1.plot(t,expo(t,coefs[0],coefs[1],coefs[2]),"-",label="fit")
ax1.legend()
plt.show()

问题是curve_fit() 返回非常大或非常小的系数a、b 和c,而它应该返回更像a = -10.5b = -0.2c = 10.5

解决方法

拟合过程通过找到损失函数的局部最小值来工作。 如果问题是不受约束的,可能有几个这样的局部最小值, 每个给出不同的参数值,你可能会得到不同的 比您期望的要好。

如果您猜测参数应该是什么,您可以提供它以缩小搜索范围:

# with an initial guess for values of a,b,c 
coefs = curve_fit(expo,t,data,p0=[-10,-1,10])[0]

它产生的系数是:

array([-10.48815244,-0.2091102,10.56699883])

或者,您可以为参数指定键:

# with lower and upper bounds for a,c
coefs = curve_fit(expo,bounds=([-20,-2,0],[-10,2,20]))[0]

这给出了与上面相同的结果。

,

可能在您的软件中实现了非线性回归算法。

启动迭代过程需要参数的“猜测”初始值。如果用户没有提供初始值,软件会评估一些初始值。这通常是失败的原因,因为计算出的初始值可能与正确值相差太远。

使用不需要初始值的线性回归方法可以找到一些好的初始值。请参阅下面的微积分。

enter image description here

结果是:

enter image description here

如果根据某些指定的拟合标准,上述结果的准确性不够,则需要进行非线性回归。在这种情况下,上述参数 $a,c$ 的值可以作为初始值来启动迭代演算。

注意:如上所示的线性化非线性回归方法的原理在:https://fr.scribd.com/doc/14674814/Regressions-et-equations-integrales

,

这是我尝试过的,在 np.exp 中使用了负 b

def expo(x,a,c): 
   return a*np.exp(-b*x) + c

>>>[-10.4881516    0.20911016  10.5669989 ]