您可能会发现
lmfit
包 (
http://lmfit.github.io/lmfit-py/) 对于这类问题非常有用。它提供了一种更高级的曲线拟合方法,以及比
scipy.optimize
包或
curve_fit()
函数更好的参数和模型抽象化。
对于这个问题,
lmfit
的两个重要特点是:
- 能够设置变量的边界。
curve_fit()
也可以做到这一点,但只能通过使用有序列表来设置最小/最大边界。而在 lmfit
中,边界属于 Parameter 对象。
- 有一种明确设置处理 NaN 值策略的方法,这可能会对您的拟合造成问题。
使用 lmfit,您的脚本将编写为:
import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model
def logfunc(T, a, b, c):
return (a*np.log(b-T))+c
log_model = Model(logfunc, nan_policy='raise')
params = log_model.make_params(a=0.5, b=2.0, c=0.5)
params['b'].min = 1.8
params['b'].max = 2.6
params['c'].min = 0.1
result = log_model.fit(np.log(Energy), params, T=T)
print(result.fit_report())
plt.plot(T, Energy, 'bo', label='data')
plt.plot(T, np.exp(result.best_fit), 'r--', label='fit')
plt.legend()
plt.xlabel('T')
plt.ylabel('Energy')
plt.gca().set_yscale('log', basey=10)
plt.show()
这个脚本比你的起始脚本稍微冗长一些,因为它提供了一个带标签的图表,而且使用参数对象而不是标量可以提供更多的灵活性和清晰度。
对于您的拟合,您可能考虑将nan_policy
设置为'omit',这样会在出现NaN时省略它们——虽然这从来不是一个好主意,但有时有助于帮助您找到log(b-T)
有效的位置。您还可以修改模型函数以执行类似的操作
def logfunc(T, a, b, c):
arg = b - T
arg[np.where(arg < 1.e-16)] = 1.e-16
return a*np.log(arg) + c
为明确防止NaN的一个明显原因。
T
在 0.3 和 3.2 之间,当b
被限制在 1.8 和 2.8 之间时,你认为log(b-T)
的结果会是什么?(同时我不确定初始值是否都为 1,无论边界如何。) - MB-Fp0
可能是一个好主意。此外,如果min(b) < max(T)
,就会遇到问题。因此,应该检查这一点。最后的问题是:为什么不适合指数版本呢?这样就可以避免log( negativNumber )
问题。 - mikuszefski