问题
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