如何只为一个参数设置边界

How to set bounds for only one parameter

我正在使用 scipy.optimize 中的 curve_fit 来拟合我的数据。我有一个适合三个参数(Z1、Z2、Z3)的函数。我想提供界限。但是,我只想提供对 Z2 的限制(Z2 应低于 40)。我不想为 Z1 和 Z3 设置界限。那可能吗?

            popt, pcov = curve_fit(func, xdata, ydata, p0 = [Z1, Z2, Z3],
                           bounds = ((10, 20, 5), (100, 50, 100,)))

            # This way I provide bounds to Z1, Z2 and Z3
            # I, however, only want to say that Z2 < 40
            # Also interesting would be to say Z2 < Z1, with no bounds for Z1 or Z3

来自documentation :

bounds: 2-tuple of array_like, optional

Lower and upper bounds on parameters. Defaults to no bounds. Each element of the tuple must be either an array with the length equal to the number of parameters, or a scalar (in which case the bound is taken to be the same for all parameters.) Use np.inf with an appropriate sign to disable bounds on all or some parameters.

所以您只需要提供 np.inf 作为上限和 -np.inf 作为 Z1 和 Z3 的下限:

import numpy as np
popt, pcov = curve_fit(func, xdata, ydata, p0 = [Z1, Z2, Z3],
                           bounds = ((-np.inf, -np.inf, -np.inf), (np.inf, 40, np.inf)))

这里我提供了一个pseudo-code解决方案,它只使用参数的重新映射而不是实际的边界条件

最初我们会做这样的事情:

bestA, bestB, bestC = fit( function( x, a, b, c, guesses=( guessA, guessB, guessC) ) )

但是,我们想要 b < c 的限制。在这种情况下,我们适合以下(省略猜测)

wrapper_function( x, a, d, c ) = function( x, a, c - d**2, c )   
bestA, bestD, bestC = fit( wrapper_function( x, a, d, c ) )

像这样发送到 function() 的值 b 将始终小于 c。 假设拟合收敛,我们只需计算 b = c - d**2。如果我们也对 b 的错误感兴趣,我们必须做 error-propagation 包括相关性。 (参见例如 Joel Tellinghuisen, J. Phys. Chem. A 2001, 105, 3917-3921)

所以s_b**2 = gT V g。其中 V 是 variance-covariance 矩阵,g = df/duu in [a, d, c]。即gT=(0, -2 * bestD, 1 ).

现在我们要 b < min( c, 40 )。也就是说,正如我的评论中提到的,有点复杂,但也是可能的。我们重写包装函数并有

wrapper_function( x, a, d, c ) = function( x, a, 0.5 * ( c + 40 - abs( c - 40 ) ) - d**2, c )   
bestA, bestD, bestC = fit( wrapper_function( x, a, d, c ) )

这可能并不明显,但如果绘制 0.5 * ( c + 40 - abs( c - 40 ) ) 它就会变得清晰。再次直接计算 b。不过,对于错误,我们必须小心计算 g。我们得到

g = ( 0, -2 * bestD, 1 - numpy.heaviside( bestC - 40, 0.5 ) )

注意:如果 c 的值和误差使得重新映射的不连续性在误差范围内,则需要重新考虑。