Why does the order of function order matter? - python

I am having a problem with a function I am trying to fit to some data. I have a model, given by the equation inside the function which I am using to find a value for v. However, the order in which I write the variables in the function definition greatly effects the value the fit gives for v. If, as in the code block below, I have def MAR_fit(v,x) where x is the independent variable, the fit gives a value for v hugely different from if I have the definition def MAR_fit(x,v). I haven't had a huge amount of experience with the curve_fit function in the scipy package and the docs still left me wondering.
Any help would be great!
def MAR_fit(v,x):
return (3.*((2.-1.)**2.)*0.05*v)/(2.*(2.-1.)*(60.415**2.)) * (((3.*x*((2.-1.)**2.)*v)/(60.415**2.))+1.)**(-((5./2.)-1.)/(2.-1.))
x = newCD10_AVB1_AMIN01['time_phys'][1:]
y = (newCD10_AVB1_AMIN01['MAR'][1:])
popt_tf, pcov = curve_fit(MAR_fit, x, y)

Have a look at the documentation again, it says that the callable that you pass to curve_fit (the function you are trying to fit) must take the independent variable as its first argument. Further arguments are the parameters you are trying to fit. You must use MAR_fit(x,v) because that is what curve_fit expects.

Related

how to update parameter and pass to solve_ivp in Python

In my ODE function I need to iteratively solve an equation for a parameter until convergence at each time step. I'd like to pass the latest parameter value to be used as the initial value for the next time step so when the function does the iterative update of the parameter it will take less time. But I can't figure out how to do that. The code structure of the ODE function is like this:
from scipy.integrate import solve_ivp
def run(t, y):
if t==0:
a = 1e-8
nn = 0
while nn<=100:
nn = nn +1
#update a until convergence
return a*y
In some one language I can return the updated parameter to be used by the integrator, but I don't' see how that's possible with solve_ivp
It's not clear what you're after: do you want to obtain a solution for an ODE at a series of parameter values (i.e. for each value of the parameter you solve the full ODE) or you are changing the parameter along with the ODE iterations (IOW, you want inner or outer iterations).
If the former, then just do a for loop over the parameters. If the latter, it's likely easier and cleaner to use solver classes which implement specific solvers (DOPRI, Radau, RK, BDF etc), which solve_ivp delegates the work to. They offer a step method, which performs a single step. So that you can adjust you parameters, control convergence etc on a way that's most relevant to this particular case.
I think what you are looking for is something in the following form:
class test:
a = 1e-8
def f(self, t, y):
## do iter on self.a
return self.a*y
t = test()
# solve_ivp(t.f, .....)
This way you can always use the last value of a, since it is part of your instance of the test class. This is not exactly what you are asking for, since this will call the iteration each time solve_ivp evaluates f, which will be multiple times per timestep. However, I think this is the closest you can get, since solve_ivp does not appear to have a callback function to invoke after each timestep

Generating function derivative as Python callable function

I was reading this question and I was trying to do the same, but I want the function to have a single parameter say x. And that parameter is an array of "values" to be filled by an optimization solver. For instance:
def f(x):
return x[0]**2 + 3*x[1]
That function will refer to: f(x)=x^2 + 3y, meaning x is an array of variables. Those variables will be present on the current function or not, because they are all the variables in the whole optimization problem, meaning they can be present on the constraints. So I will like to find that functions partial derivatives of all variables. So,in this case, i will need 2 callable functions so I can use it to form a new array that is the Jacobian of the function. Is there a way to do that? How?
Disclaimer: I am the author of pyneqsys.
If you are open to using a library, pyneqsys does exactly this. If not, you can look at the source of pyneqsys/symbolic.py which (approximately) does this to calculate the jacobian:
f = sympy.Matrix(self.nf, 1, self.exprs)
x = sympy.Matrix(self.nx, 1, self.x)
J = f.jacobian(x)
You then need to use sympy.lambdify to obtain a callable with the expected syntax of your particular solver.

How to evaluate single integrals of multivariate functions with Python's scipy.integrate.quad?

There is a function I am trying to integrate in Python using scipy.integrate.quad. This particular function takes two arguments. There is only one argument I want to integrate over. An example is shown below.
from scipy import integrate as integrate
def f(x,a): #a is a parameter, x is the variable I want to integrate over
return a*x
result = integrate.quad(f,0,1)
This example doesn't work (as is likely clear to you) since, as Python reminds me when I try it:
TypeError: f() takes exactly 2 arguments (1 given)
I am wondering how to use integrate.quad() to integrate in a single variable sense when the function given is, in general, a multi-variable function, with the extra variables providing parameters to the function.
Found the answer in the scipy documentation.
You can do the following:
from scipy import integrate as integrate
def f(x,a): #a is a parameter, x is the variable I want to integrate over
return a*x
result = integrate.quad(f,0,1,args=(1,))
The args=(1,) argument in the quad method will make a=1 for the integral evalution.
This can also be carried to functions with more than two variables:
from scipy import integrate as integrate
def f(x,a,b,c): #a is a parameter, x is the variable I want to integrate over
return a*x + b + c
result = integrate.quad(f,0,1,args=(1,2,3))
This will make a=1, b=2, c=3 for the integral evaluation.
The important thing to remember for the function you want to integrate this way is to make the variable you want to integrate over the first argument to the function.
Use the args argument (see the scipy documentation):
result = integrate.quad(f,0,1, args=(a,))
The comma in args=(a,) is required because a tuple must be passed.

Why is my python lmfit leastsq fitting function being passed too many arguments?

I've tried to search for someone making the same mistake as me, but have had no joy! It's also my 1st post, so I apologise if it's badly explained or directed. Advice welcome.
The problem I am solving is: Finding the position of a receiver of some kind by measuring the distances to a number of known reference points. It's basic trilateration, and I am using least squares to do this.
I have successfully used the scipy.optimize lesatsq function already to do this, so I'm pretty sure my fitting function works. However, I want to be able to use some of the extra features that the lmfit Python package offers, and I'm struggling to translate it accross. Full attempt code is here: http://pastebin.com/4xbfkaCm
The lmfit minimize function sets up calls to my fitting function, (which is called residualfunct) as follows, with stationarray being a numpy array containing station locations and ranges and params being a dictionary of parameters to be used in the fitting function
position = minimize(residualfunct, params, args=(stationarray))
and my fitting function is defined as
def residualfunct(params, stationarray):
X = params['solutionX'].value
Y = params['solutionY'].value
Z = params['solutionZ'].value
result = numpy.array([s[3] - linalg.norm(array((X,Y,Z))-array((s[0],s[1],s[2]))) for s in stationarray])
print result
return result
When I run this code I get the TypeError:
residualfunct() takes exactly 2 arguments (5 given).
as this call is made by the minimize function, I don't see what control I have over this. I can only imagine that this is being raised because I am passing an np.array as an argument, but this seems unavoidable. Can anyone see what I am doing wrong?
Thanks
In the call to minimize, change
args=(stationarray)
to
args=(stationarray,)
args must be a sequence (typically a tuple) whose elements are the arguments passed to the function. To create a tuple of length 1, you need the extra comma. When you write args=(stationarray) (without the extra comma), the parentheses have no effect, and it is the same as writing args=stationarray. minimize then calls the function as residualfunct(params, stationarray[0], stationarray[1], ...), which results in the error that you reported.

scipy 'Minimize the sum of squares of a set of equations'

I face a problem in scipy 'leastsq' optimisation routine, if i execute the following program it says
raise errors[info][1], errors[info][0]
TypeError: Improper input parameters.
and sometimes index out of range for an array...
from scipy import *
import numpy
from scipy import optimize
from numpy import asarray
from math import *
def func(apar):
apar = numpy.asarray(apar)
x = apar[0]
y = apar[1]
eqn = abs(x-y)
return eqn
Init = numpy.asarray([20.0, 10.0])
x = optimize.leastsq(func, Init, full_output=0, col_deriv=0, factor=100, diag=None, warning=True)
print 'optimized parameters: ',x
print '******* The End ******'
I don't know what is the problem with my func optimize.leastsq() call, please help me
leastsq works with vectors so the residual function, func, needs to return a vector of length at least two. So if you replace return eqn with return [eqn, 0.], your example will work. Running it gives:
optimized parameters: (array([10., 10.]), 2)
which is one of the many correct answers for the minimum of the absolute difference.
If you want to minimize a scalar function, fmin is the way to go, optimize.fmin(func, Init).
The issue here is that these two functions, although they look the same for a scalars are aimed at different goals. leastsq finds the least squared error, generally from a set of idealized curves, and is just one way of doing a "best fit". On the other hand fmin finds the minimum value of a scalar function.
Obviously yours is a toy example, for which neither of these really makes sense, so which way you go will depend on what your final goal is.
Since you want to minimize a simple scalar function (func() returns a single value, not a list of values), scipy.optimize.leastsq() should be replaced by a call to one of the fmin functions (with the appropriate arguments):
x = optimize.fmin(func, Init)
correctly works!
In fact, leastsq() minimizes the sum of squares of a list of values. It does not appear to work on a (list containing a) single value, as in your example (even though it could, in theory).
Just looking at the least squares docs, it might be that your function func is defined incorrectly. You're assuming that you always receive an array of at least length 2, but the optimize function is insanely vague about the length of the array you will receive. You might try writing to screen whatever apar is, to see what you're actually getting.
If you're using something like ipython or the python shell, you ought to be getting stack traces that show you exactly which line the error is occurring on, so start there. If you can't figure it out from there, posting the stack trace would probably help us.

Categories

Resources