的文档字符串optimize.curve_fit
说,
p0 : None, scalar, or M-length sequence
Initial guess for the parameters. If None, then the initial
values will all be 1 (if the number of parameters for the function
can be determined using introspection, otherwise a ValueError
is raised).
因此,首先,参数的初始猜测默认为 1。
此外,曲线拟合算法必须针对各种参数值对函数进行采样。最初选择“各种值”时的初始步长约为 1。如果您的数据随着参数值的变化而平滑地变化(大约为 1),则该算法将运行得更好。
如果函数随着 1 级的参数变化而剧烈变化,那么算法可能会倾向于错过最佳参数值。
请注意,即使该算法在调整参数值时使用了自适应步长,如果初始调整离目标太远而产生较大的残差,并且如果在其他方向上的调整恰好产生较小的残差,那么该算法可能会在错误的方向上徘徊并错过局部最小值。它可能会找到其他一些(不需要的)局部最小值,或者根本无法收敛。因此,使用具有自适应步长的算法不一定会节省您的时间。
这个故事的寓意是,扩展数据可以提高算法找到所需最小值的机会。
当应用于数量级为 1 的数据时,数值算法通常都倾向于更好地工作。这种偏差以多种方式进入算法。例如,optimize.curve_fit
依赖optimize.leastsq
,其调用签名为optimize.leastsq
:
def leastsq(func, x0, args=(), Dfun=None, full_output=0,
col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8,
gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None):
因此,默认情况下,公差ftol
和xtol
的数量级为 1e-8。如果找到最佳参数值需要小得多的容差,那么这些硬编码的默认数字将导致optimize.curve_fit
错过优化参数值。
为了使这一点更具体,假设您试图最小化f(x) = 1e-100*x**2
. 1e-100 的因子将 - 值压缩得y
如此之多,以至于大范围的 -x
值(上面提到的参数值)将适合 1e-8 的容差。因此,如果缩放不理想,leastsq
将无法很好地找到最小值。
使用大约 1 的浮点数的另一个原因是,间隔中的 (IEEE754) 浮点数[-1,1]
比远离 1 的浮点数多得多。例如,
import struct
def floats_between(x, y):
"""
http://stackoverflow.com/a/3587987/190597 (jsbueno)
"""
a = struct.pack("<dd", x, y)
b = struct.unpack("<qq", a)
return b[1] - b[0]
In [26]: floats_between(0,1) / float(floats_between(1e6,1e7))
Out[26]: 311.4397707054894
这表明表示 0 和 1 之间数字的浮点数是区间 [1e6, 1e7] 中的浮点数的 300 多倍。因此,在其他条件相同的情况下,如果使用小数字而不是非常大的数字,您通常会得到更准确的答案。