符合scipy.optimize参数的错误

Ant*_*nin 4 numpy curve-fitting scipy

我将scipy.optimize.minimizehttps://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html)函数与结合使用method='L-BFGS-B

上面返回的示例如下:

      fun: 32.372210618549758
 hess_inv: <6x6 LbfgsInvHessProduct with dtype=float64>
     jac: array([ -2.14583906e-04,   4.09272616e-04,  -2.55795385e-05,
         3.76587650e-05,   1.49213975e-04,  -8.38440428e-05])
  message: 'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
     nfev: 420
      nit: 51
   status: 0
  success: True
        x: array([ 0.75739412, -0.0927572 ,  0.11986434,  1.19911266,  0.27866406,
       -0.03825225])
Run Code Online (Sandbox Code Playgroud)

x值正确包含适合的参数。如何计算与这些参数相关的误差?

Mik*_*ike 5

TL; DR:实际上,您可以为最小化例程找到参数最佳值的精确度设置一个上限。请参见此答案末尾的代码片段,该代码片段显示了如何直接执行此操作,而无需诉诸其他最小化例程。


该方法的文档

迭代在时停止(f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= ftol

粗略地说,当f您要最小化的函数的值最小化到ftol最佳范围内时,最小化就会停止。(如果f大于1,则是一个相对误差,否则,则是绝对误差;为简单起见,我将假定它是绝对误差。)在更标准的语言中,您可能会将函数f视为卡方值。因此,这大致表明您会期望

\ chi ^ 2 _ {\ mathrm {found}}-\ chi ^ 2 _ {\ mathrm {optimal}} \ lesssim \ mathtt {ftol}

当然,实际上,您正在应用这样的最小化例程的事实就认为您的函数运行良好,从某种意义上来说,它是相当平滑的,并且通过参数x的二次函数可以很好地近似所求出的最优值

\ chi ^ 2 _ {\ mathrm {found}}-\ chi ^ 2 _ {\ mathrm {optimal}} \ approx \ sum_ {i,j} H_ {ij} \ Delta x ^ i \ Delta x ^ j

在哪 x i是参数x i的找到的值与其最佳值之间的差,并且H ij是黑森州矩阵。一个小的(令人惊讶的是非平凡的)线性代数可以使您得到一个相当标准的结果,用于估计作为参数x i的函数的任何数量X的不确定性:

(\ Delta X)^ 2 = \ left(\ chi ^ 2 _ {\ mathrm {found}}-\ chi ^ 2 _ {\ mathrm {optimal}} \ right)\ sum_ {i,j} \ left(H ^ { -1} \ right)_ {ij} \\ frac {\ partial X} {\ partial x ^ i} \ frac {\ partial X} {\ partial x ^ j}

让我们写

(\ Delta X)^ 2 \ lesssim \ mathtt {ftol} \ sum_ {i,j} \ left(H ^ {-1} \ right)_ {ij} \\ frac {\ partial X} {\ partial x ^ i} \ frac {\ partial X} {\ partial x ^ j}

通常,这是最有用的公式,但是对于这里的特定问题,我们只有X = x i,因此这简化为

\ Delta x ^ i \ lesssim \ sqrt {\ mathtt {ftol} \ left(H ^ {-1} \ right)_ {ii}}

最后,要完全明确地说,假设您将优化结果存储在名为的变量中res。逆Hessian可作为来使用res.hess_inv,该函数采用一个向量,并返回该逆Hessian与该向量的乘积。因此,例如,我们可以使用如下代码段显示优化的参数以及不确定性估计:

ftol = 2.220446049250313e-09
tmp_i = np.zeros(len(res.x))
for i in range(len(res.x)):
    tmp_i[i] = 1.0
    hess_inv_i = res.hess_inv(tmp_i)[i]
    uncertainty_i = np.sqrt(max(1, abs(res.fun)) * ftol * hess_inv_i)
    tmp_i[i] = 0.0
    print('x^{0} = {1:12.4e} ± {2:.1e}'.format(i, res.x[i], uncertainty_i))
Run Code Online (Sandbox Code Playgroud)

请注意,我已经max从文档中合并了该行为,并假设f^kf^{k+1}基本上与最终输出值相同res.fun,这实际上应该是一个很好的近似值。另外,对于小问题,您可以使用np.diag(res.hess_inv.todense())来获取完整的逆,并一次提取对角线。但是对于大量变量,我发现这是一个慢得多的选择。最后,我添加了默认值ftol,但是如果您在的参数minimize中将其更改,则显然需要在此处进行更改。