Scipy.Optimise Curve_fit 的指数拟合不起作用
Posted
技术标签:
【中文标题】Scipy.Optimise Curve_fit 的指数拟合不起作用【英文标题】:Exponential Fitting with Scipy.Optimise Curve_fit not working 【发布时间】:2014-05-29 16:49:24 【问题描述】:我正在尝试使用 Scipy.Optimise Curve_fit 按照简单示例 here 来拟合某些数据的指数。
脚本运行时没有错误,但是非常糟糕。当我在 curve_fit 的每一步查看 popt 的输出时,从初始参数跳到一系列 1.0 似乎并没有很好地迭代,尽管它似乎使第三个参数恢复到一个不错的值:
92.0 0.01 28.0
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
1.00012207031 1.0 1.0
1.0 1.00012207031 1.0
1.0 1.0 1.00012207031
1.0 1.0 44.3112882656
1.00012207031 1.0 44.3112882656
1.0 1.00012207031 44.3112882656
1.0 1.0 44.3166973584
1.0 1.0 44.3112896048
1.0 1.0 44.3112882656
我不确定是什么导致了这种情况,除非该模型与数据不太吻合,尽管我强烈怀疑它应该(物理学就是物理学)。有人有什么想法吗?我在下面发布了我的(非常简单的)脚本。谢谢。
#!/usr/bin/python
import matplotlib.pyplot as plt
import os
import numpy as np
from scipy.optimize import curve_fit
from matplotlib.ticker import*
from glob import glob
from matplotlib.backends.backend_pdf import PdfPages
import fileinput
path_src=os.getcwd()
dirlist= glob(path_src + '/Gel_Temp_Res.txt')
dirlist.sort()
plots_file='Temp_Curve.pdf'
plots= PdfPages(path_src+'/'+plots_file)
time=[]
temp=[]
for row in fileinput.input(path_src + '/Gel_Temp_Res.txt'):
time.append(row.split()[0])
temp.append(row.split()[1])
nptime=np.array(time, dtype='f')
nptemp=np.array(temp, dtype='f')
del time[:]
del temp[:]
# Newton cooling law fitting
def TEMP_FIT(t, T0, k, Troom):
print T0, k, Troom
return T0 * np.exp(-k*t) + Troom
y = TEMP_FIT(nptime[41:], nptemp[41]-nptemp[0], 1e-2, nptemp[0])
yn = y + 0.2*np.random.normal(size=len(nptime[41:]))
popt, pcov = curve_fit(TEMP_FIT, nptime[41:], yn)
# Plotting
ax1 = plt.subplot2grid((1,1),(0, 0))
ax1.set_position([0.1,0.1,0.6,0.8])
plt.plot(nptime[41:], nptemp[41:], 'bo--',label='Heater off', alpha=0.5)
plt.plot(nptime[41:], TEMP_FIT(nptime[41:], *popt), label='Newton Cooling Law Fit')
plt.xlim(-25, 250)
plt.xlabel('Time (min)')
plt.ylabel('Temperature ($^\circ$C)')
ax1.grid(True, which='both', axis='both')
plt.legend(numpoints=1, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
plt.savefig(plots, format='pdf',orientation='landscape')
plt.close()
plots.close()
另外,这是我试图拟合的数据:
100 124
130 120
135 112
140 105
145 99
150 92
155 82
160 75
165 70
170 65
175 60
180 56
185 55
190 52
195 49
200 45
205 44
210 40
215 39
220 37
225 35
【问题讨论】:
【参考方案1】:大的负指数使指数函数接近于零,从而使最小二乘算法对您的拟合参数不敏感。
因此,在根据时间戳用指数拟合指数函数时,最好通过排除第一个数据点的时间来调整时间指数,将其更改为:
f = exp(-x*t)
到:
t0 = t[0] # place this outside loops
f = exp(-x*(t - t0))
将此概念应用于您的代码会导致:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
time, temp = np.loadtxt('test.txt', unpack=True)
t0 = time[0]
# Newton cooling law fitting
def TEMP_FIT(t, T0, k, Troom):
print(T0, k, Troom)
return T0 * np.exp(-k*(t - t0)) + Troom
popt, pcov = curve_fit(TEMP_FIT, time, temp)
# Plotting
plt.figure()
plt.plot(time, temp, 'bo--',label='Heater off', alpha=0.5)
plt.plot(time, TEMP_FIT(time, *popt), label='Newton Cooling Law Fit')
plt.xlim(-25, 250)
plt.xlabel('Time (min)')
plt.ylabel('Temperature ($^\circ$C)')
ax = plt.gca()
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.legend(fontsize=8)
plt.savefig('test.png', bbox_inches='tight')
结果是:
删除样本的第一个点:
【讨论】:
太好了,谢谢 Saullo。所以只是为了澄清,你认为curve_fit不能处理非零起始x位置?问题是,我实际上有更多超出这个范围的数据,所以我实际上只对拟合一个部分感兴趣。我唯一的选择是从 0 开始创建人工拟合范围吗? 不能处理的不是curve_fit,而是你的模型。如果您向模型添加时移,它将正常工作。 T0 * np.exp(-k*(t-t0)) + Troom @user34716time
从任意值开始的问题是它的exp
将返回一个巨大的数字,这样最佳参数对x
的值的敏感性接近数值精度阈值。这个问题不是curve_fit
以上是关于Scipy.Optimise Curve_fit 的指数拟合不起作用的主要内容,如果未能解决你的问题,请参考以下文章
为啥 scipy.optimize.curve_fit 不适合数据?
scipy.optimize.curve_fit 的替代方案
Curve_fit 在大于参数本身的参数上给出错误(Python)