Zhi*_* Li 1 python math curve-fitting numerical-methods
我是编程工具和 Python 的新手,对数值计算知之甚少。我试图理解Curve_fit的源代码,但对我来说太难了。
如果我们立即曲线拟合非线性模型,通过计算 Hessian 矩阵,我想我们能够找到所有参数的临界点,无论是局部还是全局,以及最小值或最大值。
但是,如果包含模型的函数无法微分,curve_fit 实际如何计算答案?
我想象该算法是在所有数据点的每个参数的每个间隔中找到 Chi^2 的局部最小值。如果这样做,默认间隔是多大,参数的每次试验之间的距离是多少,最大迭代次数是多少?如果像我说的那样,这个迭代在多个参数之间是如何工作的?他们每次都作为一组单独尝试吗?
我想了解算法,以便我可以编写一个很好的函数来应用curve_fit。我试图适应的函数中存在许多脏修复,不同的错误出现在不同的小更改中,因此我无法将代码放在这里,因为我不知道问题所在。
另外,关于 sigma 输入,如果我不知道 y 错误,如果默认 sigma 与数据值相比太大,结果会怎样?或者,如果模型的灵活性对后期处理影响不大,或者 sigma 远小于数据到函数的距离,会发生什么?
要开始了解 scipy 如何curve_fit
尝试解决问题,请首先阅读非线性优化方法,例如 Levenberg-Marquardt (LM) 方法(请参阅https://en.wikipedia.org/wiki/Levenberg%E2%80% 93Marquardt_algorithm)。这是curve_fit
未指定参数值界限时使用的方法,它将提供您寻求的大部分答案。
此方法(以及 中的其他求解器scipy.optimize
)从初始值开始并尝试细化这些值以找到最小的结果残差数组(在最小二乘意义上:明确地说,该方法需要一个残差数组并进行平方并求和)。为了找到移动参数值的方向,它使用一阶导数(残差 wrt 到变量的)或雅可比。对此没有解析形式是很常见的,在这种情况下,数值导数是通过在参数值中采用非常小的步长(通常围绕机器精度)来计算的。
有了这些导数和最后一步的大小,LM 方法决定了寻找最小残差的步长。将残差视为每个参数的二次函数是一种常见的(通常也是一种很好的)近似方法。如果该值远离底部,则在导数中采取线性的步长(即,仅跟随局部斜率)是相当好的。但是在接近最终解决方案时,使用二阶导数(又名 Hessian、曲率或某种意义上的“历史”)会很有帮助。LM 结合了这两种方法来尝试快速找到解决方案。在每一步,它首先计算导数(和第一步之后的二阶导数),然后计算所有参数的步长。它重复此过程,直到解(卡方)与容差相比没有改善。在 scipy 的leastsq
(通常由 使用curve_fit
)用于计算数值导数的步长,并且可以指定停止拟合的容差。
通常,在使用curve_fit
orleastsq
或 时least_squares
,您无需担心有关如何找到解决方案的任何这些细节。好吧,除了如果您确实有解析导数,它可以提高过程的速度和准确性。您的“模型函数”应该只采用传入的参数并计算数据的预测模型。更改传入的值会混淆算法——它正在使用它知道的值运行您的函数,以尝试找到解决方案。
其他问题:
如果您不知道数据中的标准误差 ( y
),请不要太担心。报告卡方的绝对值可能不接近ndata-nvarys
(正如预期的良好拟合),但相对于其他拟合的值应该没问题。
LM 方法的特征之一(至少在 MINPACK -> leastsq
->curve_fit
实现中)是它报告最终的协方差矩阵,可用于确定拟合参数中的不确定性和相关性。通常,报告的值应将卡方增加 1(即1-sigma
标准误差)。因为数据没有很好的不确定性是很常见的,所以 scipycurve_fit
缩放这个协方差来给出值,就好像卡方确实等于ndata-nvarys
。也就是说,如果您认为拟合良好(并且sqrt(chi-square/(ndata-nvays))
可用于估计数据中的误差),则参数中的标准误差将非常好。