我正在尝试计算两种形式的指数对某些x, y
数据的最佳拟合(数据文件可以从here下载)
以下是代码:
from scipy.optimize import curve_fit
import numpy as np
# Get x,y data
data = np.loadtxt('data.txt', unpack=True)
xdata, ydata = data[0], data[1]
# Define first exponential function
def func(x, a, b, c):
return a * np.exp(b * x) + c
# Get parameters estimate
popt, pcov = curve_fit(func, xdata, ydata)
print popt
# Define second exponential function (one more parameter)
def func2(x, a, b, c, d):
return a * np.exp(b * x + c) + d
# Get parameters estimate
popt2, pcov2 = curve_fit(func2, xdata, ydata)
print popt2
第一个指数为popt
提供与zunzun.com(PDF here)完全相同的值:
[ 7.67760545e-15 1.52175476e+00 2.15705939e-02]
但是第二个给出popt2
明显错误的值:
[ -1.26136676e+02 -8.13233297e-01 -6.66772692e+01 3.63133641e-02]
这是相同第二个函数的zunzun.com值(PDF here):
a = 6.2426224704624871E-15
b = 1.5217697532005228E+00
c = 2.0660424037614489E-01
d = 2.1570805929514186E-02
我尝试将列表数组设为Strange result with python's (scipy) curve fitting,但这没有帮助。我在这里做错了什么?
我猜这个问题与缺少初始值有关我正在提供我的功能(如下所述:gaussian fit with scipy.optimize.curve_fit in python with wrong results)
如果我将估算值从第一个指数提供给第二个指数(如此)(使新参数d
最初为零):
popt2, pcov2 = curve_fit(func2, xdata, ydata, p0 = [popt[0], popt[1], popt[2], 0])
与zunzun.com相比,我得到的结果更合理但仍然错误:
[ 1.22560853e-14 1.52176160e+00 -4.67859961e-01 2.15706930e-02]
所以现在问题改为:如何自动为第二个函数提供更合理的参数?
答案 0 :(得分:2)
Zunzun.com使用差分进化遗传算法(DE)来找到初始参数估计值,然后将其传递给scipy中的Levenberg-Marquardt求解器。 DE实际上并不是用作全局优化器本身,而是用作“初始参数猜测器”。
您可以在任何网站的网页底部找到zunzun.com fitter的BSD许可Python源代码的链接 - 它有许多全面的示例 - 因此不需要立即编写代码。如果您有任何问题,请告诉我,我会尽力帮助您。
詹姆斯菲利普斯 zunzun@zunzun.com答案 1 :(得分:1)
请注意zunzun估算中的a=0
以及您的第一个模型。所以他们只是估计一个常数。因此,第一种情况下的b
和第二种情况下的b
和c
无关紧要且无法识别。
Zunzun也使用差分进化作为全局求解器,这是我最后一次看到它。 Scipy现在将流水作为全局优化器看起来相当不错,在可能出现局部最小值的情况下值得一试。
我的“便宜”方式,因为参数在您的示例中没有大范围:尝试随机起始值
np.random.seed(1)
err_last = 20
best = None
for i in range(10):
start = np.random.uniform(-10, 10, size=4)
# Get parameters estimate
try:
popt2, pcov2 = curve_fit(func2, xdata, ydata, p0=start)
except RuntimeError:
continue
err = ((ydata - func2(xdata, *popt2))**2).sum()
if err < err_last:
err_last = err
print err
best = popt2
za = 6.2426224704624871E-15
zb = 1.5217697532005228E+00
zc = 2.0660424037614489E-01
zd = 2.1570805929514186E-02
zz = np.array([za,zb,zc,zd])
print 'zz', zz
print 'cf', best
print 'zz', ((ydata - func2(xdata, *zz))**2).sum()
print 'cf', err_last
最后一部分打印(zz是zunzun,cf是curve_fit)
zz [ 6.24262247e-15 1.52176975e+00 2.06604240e-01 2.15708059e-02]
cf [ 1.24791299e-16 1.52176944e+00 4.11911831e+00 2.15708019e-02]
zz 9.52135153898
cf 9.52135153904
与b
和c
的Zunzun不同的参数,但相同的残差平方和。
<强>加成强>
a * np.exp(b * x + c) + d = np.exp(b * x + (c + np.log(a))) + d
或
a * np.exp(b * x + c) + d = (a * np.exp(c)) * np.exp(b * x) + d
第二个功能与第一个功能没有什么不同。 a
和c
未单独标识。因此,使用衍生信息的优化器也会遇到问题,因为如果我正确地看到这个,Jacobian在某些方向上是单数的。