我有一组数据,我想通过使用python来拟合指数曲线。我看了几个例子,我想出了下面的一段脚本。
from pylab import rc
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from scipy import optimize
def model_func(t, A, K, C):
return A * np.exp(-K*t) + C
def fit_exp_nonlinear(t, y):
opt_parms, parm_cov = optimize.curve_fit(model_func, t, y, maxfev=10000)
A, K, C = opt_parms
return A, K, C
pi_1_3 = np.array([186774.67608906, 119480.98881671, 81320.7163753 ,
58031.00546565, 42990.04111078, 32826.01571713,
25700.16102843, 20548.41187945, 16726.83116009,
13828.25419449, 11587.30623606, 9825.34010814,
8419.5903399 , 7283.07702701, 6353.54595154,
5585.14190098, 4943.96579672, 4404.19434404,
3946.30532107, 3555.02206224, 3218.38622266,
2927.06387001, 2673.47535718, 2451.61460839,
2256.54734046, 2084.28211566, 1931.48280645,
1795.43700167, 1673.85361378, 1564.82468004,
1466.7273566 , 1378.20995936, 1298.09333835,
1225.40136541, 1159.27214181, 1098.96372522,
1043.84974141, 993.36880068, 947.04676203,
904.45522954, 865.23010028, 829.04001802,
795.60459963, 764.66375969, 735.99814339,
709.40108872, 684.69988262, 661.73223448,
640.35399121, 620.44025093, 601.87371066,
584.54929565, 568.37272058, 553.26381714,
539.14562691, 525.94472176, 513.59920745,
502.05319667, 491.25259209, 481.15219684,
471.70448455, 462.87002943, 454.61638734,
446.90526636, 439.70525636, 432.99373968,
426.73945924, 420.91972403, 415.50905545,
410.49218343, 405.84570284, 401.55105219,
397.59401523, 393.95737052, 390.62344145,
387.58306896, 384.81946995, 382.319658 ,
380.06982549, 378.05960051, 376.27758291,
374.70924213, 373.34528829, 372.17106384,
371.17691362, 370.34772485, 369.67316117,
369.13731143, 368.72679983, 368.42660804,
368.22202786, 368.09453347, 368.02778592,
368.00352008, 367.99947609])
pi_2_3 = np.array([ 0.96762688, 0.96645461, 0.96574696, 0.96541101, 0.96521801,
0.96519657, 0.96540386, 0.96556112, 0.96589707, 0.96634024,
0.96686919, 0.9675554 , 0.96833452, 0.96922802, 0.97023588,
0.97134382, 0.97257327, 0.97390279, 0.97534668, 0.97689778,
0.97855611, 0.98032166, 0.98219442, 0.98417441, 0.98626876,
0.98846319, 0.99076483, 0.9931737 , 0.99556112, 0.99834167,
1.00103645, 1.00386705, 1.00680486, 1.00985704, 1.012995 ,
1.01623302, 1.01956397, 1.022995 , 1.02651894, 1.03015726,
1.0338456 , 1.03764832, 1.04152966, 1.04549678, 1.04953538,
1.05365261, 1.05784132, 1.0621015 , 1.06641887, 1.07080057,
1.07523231, 1.07970693, 1.0842173 , 1.08877055, 1.09335239,
1.09794853, 1.10255897, 1.10716941, 1.11177269, 1.11636169,
1.12092924, 1.12546104, 1.12994282, 1.13437455, 1.13874196,
1.14303074, 1.14723374, 1.15132952, 1.15531094, 1.15917798,
1.16290922, 1.1664975 , 1.16992852, 1.17320229, 1.1763045 ,
1.17922087, 1.18195854, 1.18450322, 1.18686204, 1.18902073,
1.19097212, 1.19273052, 1.19429593, 1.19566833, 1.19686204,
1.19787706, 1.19872051, 1.19941387, 1.19997141, 1.20040029,
1.20070765, 1.20092924, 1.20108649, 1.20118656, 1.20125804])
A, K, C = fit_exp_nonlinear(pi_2_3,pi_1_3)
fit_y = model_func(pi_2_3, A, K, C)
print A, K, C
fig = plt.figure(num=None, figsize=(8,16), dpi=80, facecolor='w', edgecolor='k', linewidth= 2.0, frameon=True)
fig = plt.xlabel(r'$\pi_1$', fontsize=17)
fig = plt.ylabel(r'$\pi_2$', fontsize=17)
fig = plt.autoscale(enable=True, axis='both', tight=False)
#fig = plt.ylim(0, 5)
#fig = plt.xlim(-0.1, 5e+7)
fig = plt.plot(pi_2_3, pi_1_3, linewidth=1.5, color='g', linestyle = '--', marker='s', markeredgecolor='g', markerfacecolor='white', label='measured')
fig = plt.plot(pi_2_3, fit_y, linewidth=1.5, color='k', linestyle = '-', marker='', markeredgecolor='k', markerfacecolor='white', label='fitted')
fig=plt.legend()
figE = plt.show()
然而,可以看出,A,K和C似乎没有得到很好的估计(?)。有没有更好的方法将指数曲线拟合到这些数据?
此外,python中是否有用于非线性回归分析的库?
提前多多感谢,
吉奥
答案 0 :(得分:2)
由于两个原因,你的身体状况不佳:
您可以通过将常量A
移动到指数exp(-K*(t - t_0)) + C
中来改善模型的数值条件。这种方式得到的结果与指数模型一样好。在日志空间中拟合也无济于事(只要模型中有加性常量C
,它就不是一个选项)。
答案 1 :(得分:2)
有时optimize.curve_fit
需要一点帮助,对正确球场中的参数进行初步猜测。通过指定curve_fit
参数将猜测传递给p0
。
您可能有一些独立的方式来猜测A,K,C应该基于理论或经验。例如,如果您的-K*t
值非常大(且为负数),那么当C
非常大时,您可以将model_func
估算为t
的值,因为A * np.exp(-K * t)
1}} term应该为零(假设K
不是非常小)。在任何情况下,理论都应该告诉你A,K,C的值是合理的。您可以将它们作为猜测。
这是一个2-pass方法,似乎可以在没有任何先验猜测的情况下工作。它首先尝试将数据拟合为没有常数项的partial_func
模型。然后,它使用该拟合中的A
和K
参数作为针对model_func
的curve_fit的猜测:
def model_func(t, A, K, C):
return A * np.exp(-K * t) + C
def partial_func(t, A, K):
return A * np.exp(-K * t)
def fit_exp_nonlinear(t, y):
opt_parms, parm_cov = optimize.curve_fit(partial_func, t, y, maxfev=10000)
A, K = opt_parms
opt_parms, parm_cov = optimize.curve_fit(model_func, t, y, p0=(A, K, 0))
A, K, C = opt_parms
return A, K, C
产量
A, K, C = (2.3961062737821128e+73, 163.82812722558725, 338.80276054827715)
拟合并不是很好,但考虑到数据看起来不是非常接近任何指数,它可能是最好的。