How to set bounds for only one parameter

北城以北 提交于 2021-02-11 14:44:13

问题


I'm using curve_fit from scipy.optimize to fit my data. I have a function that fits three parameters (Z1, Z2, Z3). I wannt to provide bounds. However, I'd like to only provide a bound to Z2 (Z2 shall be below 40). I do not want to set bounds for Z1 and Z3. Is that possible?

            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

回答1:


Here I provide a pseudo-code solution that uses just remapping of parameters instead of actual boundary conditions

originally we would do something like:

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

However, we want the restriction that b < c. In such a case we fit the following instead (omitting the guesses)

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

like this the value b send to function() will always be less than c. Assuming the fit converges we just calculate b = c - d**2. If we are also interested in the error of b we have to do error-propagation including correlation. ( see e.g. Joel Tellinghuisen, J. Phys. Chem. A 2001, 105, 3917-3921)

So s_b**2 = gT V g. where V is the variance-covariance matrix and g = df/du and u in [a, d, c]. That is gT=(0, -2 * bestD, 1 ).

Now we want b < min( c, 40 ). That is, as mentioned in my comment, a bit more complicated, but also possible. We rewrite the wrapper function and have

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 ) )

It might not be obvious that this does the trick, but if one plots 0.5 * ( c + 40 - abs( c - 40 ) ) it becomes clear. It is again straight forward to calculate b. For the error we have to be careful with calculating g, though. We get

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

Note: if the value and error of c are such that the discontinuity of the remapping is within error margins, this needs to be reconsidered, though.




回答2:


From the 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.

So you just need to provide np.inf as an upper bound and -np.inf as a lower bound for Z1 and 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)))


来源:https://stackoverflow.com/questions/60845538/how-to-set-bounds-for-only-one-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!