scipy.optimize.leastsq : How to specify non-parameters? - scipy

I want to know how to use leastsq from scipy for chi-square fitting. I know the structure is basically -
parameters = leastsq(chi(exp_data, exp_err, param), initial_guess, arg = (?,?,?))
where exp_data, exp_err are arrays
def fitted_data(param):
fitted_data = a*param[0] + b*param[1]**2 + c*np.sin(param[3])
return fitted_data
def chi(exp_data, exp_err, param):
chi = (exp_data - fitted_data(param))/exp_err
return(chi)
What I don't understand is how to specify only param as the parameters to explore for chi square fitting. I don't understand how to use arg = (?,?,?), as I have multiple inputs for the function chi, not just parameters.
Thank you very much.

leastsq takes a function to be minimized. This function has to be dependent on the parameters of your fit, and may additionally be dependent on other parameters, that are considered constant for the minimization. These are provided via the args-argument as a tuple. The parameters are to be provided as the first argument, and all additional arguments may follow after.
Your function to be minimized therefor needs to look like this:
def residuals(params, args)
I adjusted your code to fit these requirements:
def fitted_data(params) :
fitted_data = a*params[0] + b*params[1]**2 + c*np.sin(params[3])
return fitted_data
def chi(params, exp_data, exp_err) :
chi = (exp_data - fitted_data(params)/exp_err
return chi
result = scipy.optimize.leastsq(chi, x0=(1, 1, 1), args=(exp_data, exp_err))

Related

application of minimize_scalar

I am trying to replicate the results posted here (How to use scipy.optimize minimize_scalar when objective function has multiple arguments?) using a different structure. The goal is exactly the same but I just want to code it in a different way. Here is my code:
def mini(g,a,b,args):
object=lambda w1: g(w1, *args)
result=minimize_scalar(object, bounds=(a, b))
minzer, minval=result.x, result.fun
return minzer,minval
def errorr(w0,w1,x,y):
y_pred = w0 + w1*x
mse = ((y-y_pred)**2).mean()
return mse
x = np.array([1,2,3])
y = np.array([52,54,56])
w0=50
mini(errorr, -5, 5, (w0,x,y))
However, the results obtained using my code is quite different from the one in the original posts. I am wondering where did I make the mistake in my code that caused the different results. Thanks!
Since you use lambda w1: g(w1, *args), you are minimizing with respect to the first function argument w0. To minimize with respect to w1, you can write lambda w1: g(args[0], w1, *args[1:]) instead.
However, please avoid python keywords as variable names (e.g. object). In addition, a lambda function is an anonymous function, so assigning it to a variable contradicts its purpose. Consequently, I'd propose either
def mini(g,a,b,args):
def obj_fun(w1): return g(args[0], w1, *args[1:])
result = minimize_scalar(obj_fun, bounds=(a, b))
return result.x, result.fun
or
def mini(g,a,b,args):
result = minimize_scalar(lambda w1: g(args[0], w1, *args[1:]), bounds=(a, b))
return result.x, result.fun

How to write a flexible multiple exponential fit

I'd like to write a more or less universial fit function for general function
$f_i = \sum_i a_i exp(-t/tau_i)$
for some data I have.
Below is an example code for a biexponential function but I would like to be able to fit a monoexponential or a triexponential function with the smallest code adaptions possible.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
t = np.linspace(0, 10, 100)
a_1 = 1
a_2 = 1
tau_1 = 5
tau_2 = 1
data = 1*np.exp(-t/5) + 1*np.exp(-t/1)
data += 0.2 * np.random.normal(size=t.size)
def func(t, a_1, tau_1, a_2, tau_2): # plus more exponential functions
return a_1*np.exp(-t/tau_1)+a_2*np.exp(-t/tau_2)
popt, pcov = curve_fit(func, t, data)
print(popt)
plt.plot(t, data, label="data")
plt.plot(t, func(t, *popt), label="fit")
plt.legend()
plt.show()
In principle I thought of redefining the function to a general form
def func(t, a, tau): # with a and tau as a list
tmp = 0
tmp += a[i]*np.exp(-t/tau[i])
return tmp
and passing the arguments to curve_fit in the form of lists or tuples. However I get a TypeError as shown below.
TypeError: func() takes 4 positional arguments but 7 were given
Is there anyway to rewrite the code that you can only by the input parameters of curve_fit "determine" the degree of the multiexponential function? So that passing
a = (1)
results in a monoexponential function whereas passing
a = (1, 2, 3)
results in a triexponential function?
Regards
Yes, that can be done easily with np.broadcasting:
def func(t, a, taus): # plus more exponential functions
a=np.array(a)[:,None]
taus=np.array(taus)[:,None]
return (a*np.exp(-t/taus)).sum(axis=0)
func accepts 2 lists, converts them into 2-dim np.array, computes a matrix with all the exponentials and then sums it up. Example:
t=np.arange(100).astype(float)
out=func(t,[1,2],[0.3,4])
plt.plot(out)
Keep in mind a and taus must be the same length, so sanitize your inputs as you see fit. Or you could also directly pass np.arrays instead of lists.

sympy derivative with boolean

I am trying to take the derivative of a function including a boolean variable with sympy.
My expected result:
Two different derivatives, depending on the boolean being either True or False (i.e. 1 or 0).
Example:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
bo = sy.Function("bo")
fct1 = sy.Function("fct1")
fct2 = sy.Function("fct2")
FOC2 = sy.Function("FOC2")
y = 5
a = 2
b = 4
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
# the following gives the smaller positive intercept with the x-axis)
# this intercept is the threshold value for the boolean function, bo
min(sy.solve(fct1(x)-y, x))
def bo(x):
if fct1(x) <= y:
return 1
else:
return 0
def fct2(c, x):
return a + b*c + bo(x)*c
def FOC2(c, x):
return sy.diff(fct2(c, x), c)
print(FOC2(c, x))
The min-function after the comments shows me the threshold of x for bo being True or False would be 4.29..., thus positive and real.
Output:
TypeError: cannot determine truth value of Relation
I understand that the truth value depends on x, which is a symbol. Thus, without knowing x one cannot determine bo.
But how would I get my expected result, where bo is symbolic?
First off, I would advise you to carefully consider what is going on in your code the way it is pasted above. You first define a few sympy functions, e.g.
fct1 = sy.Function("fct1")
So after this, fct1 is an undefined sympy.Function - undefined in the sense that it is neither specified what its arguments are, nor what the function looks like.
However, then you define same-named functions explicitly, as in
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
Note however, that at this point, fct1 ceases to be a sympy.Function, or any sympy object for that matter: you overwrite the old definition, and it is now just a regular python function!
This is also the reason that you get the error: when you call bo(x), python tries to evaluate
-0.004*x**2 + 0.25*x + 4 <= 5
and return a value according to your definition of bo(). But python does not know whether the above is true (or how to make that comparison), so it complains.
I would suggest 2 changes:
Instead of python functions, as in the code, you could simply use sympy expressions, e.g.
fct1 = -0.004*x**2 + 0.25*x + 4
To get the truth value of your condition, I would suggest to use the Heaviside function (wiki), which evaluates to 0 for a negative argument, and to 1 for positive. Its implementation in sympy is sympy.Heaviside.
Your code could then look as follows:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
y = 5
a = 2
b = 4
fct1 = -0.004*x**2 + 0.25*x + 4
bo = sy.Heaviside(y - fct1)
fct2 = a + b*c + bo * c
FOC2 = sy.diff(fct2, c)
print(FOC2)
Two comments on the line
bo = sy.Heaviside(y - fct1)
(1) The current implementation does not evaluate sympy.Heaviside(0)by default; this is beacause there's differing definitions around (some define it to be 1, others 1/2). You'd want it to be 1, to be in accordance with the (weak) inequality in the OP. In sympy 1.1, this can be achieved by passing an additional argument to Heaviside, namely whatever you want Heaviside(0) to evaluate to:
bo = sy.Heaviside(y - fct1, 1)
This is not supported in older versions of sympy.
(2) You will get your FOC2, again involving a Heaviside term. What I like about this, is that you could keep working with this expression, say if you wanted to take a second derivative and so on. If, for the sake of readability, you would prefer a piecewise expression - no problem. Just replace the according line with
bo = sy.Heaviside(y - fct1)._eval_rewrite_as_Piecewise(y-fct1)
Which will translate to a piecewise function automatically. (note that under older versions, this automatically implicitly uses Heaviside(0) = 0.5 - best to use (1) and (2) together:
bo = sy.Heaviside(y - fct1, 1)._eval_rewrite_as_Piecewise(y-fct1)
Unfortunately, I don't have a working sympy 1.1 at my hands right now and can only test the old code.
One more noteconcerning sympy's piecewise functions: they are much more readable if using sympy's latex printing, by inserting
sy.init_printing()
early in the code.
(Disclaimer: I am by no means an expert in sympy, and there might be other, preferable solutions out there. Just trying to make a suggestion!)

minFunc package usage

I have been using MATLAB fminunc function to solve my optimization problem. I want to try the minFunc package :
http://www.di.ens.fr/~mschmidt/Software/minFunc.html
When using fminunc, I defined a function funObj.m which gives me the objective value and the gradient at any point 'x'. It also takes in several external inputs say, {a,b,c} which are matrices. So the function prototype looks like :
function [objVal,G] = funObj(x,a,b,c)
I want to use the same setup in the minFunc package. From the examples, I figured this should work :
options.Method='lbfgs';
f = #(x)funObj(x,a,b,c);
x = minFunc(f,x_init,options);
But when I call this way, I get an error as:
Error using funObj
Too many output arguments.
What is the correct way to call minFunc for my case?
**EDIT : Alright, here is a sample function that I want to use with minFunc. Lets say I want to find the minimum of a*(b-x)^2, where a,b are scalar parameters and x being a scalar too. The MATLAB objective function will then look like :
function obj = testFunc(x,a,b)
obj = a*(b-x)^2;
The function call to minimize this using fminunc (in MATLAB ) is simply:
f = #(x)testFunc(x,a,b);
x = fminunc(f,x_init);
This gives me the minimum of x = 10. Now, How do I do the same using minFunc ?
"Note that by default minFunc assumes that the gradient is supplied, unless the 'numDiff' option is set to 1 (for forward-differencing) or 2 (for central-differencing)."
The error is because only one argument is returned by the function. You can either return the gradient as a second argument or turn on numerical differencing.
Agree with Mark. I think the simplest way to solve it is
minFunc(#testFunc, x_init, a, b, c)
In MATLAB temporary function can only have one return value. So f = #(x)testFunc(x,a,b); let your method drop gradient part every time. Because minFunc can accept extra paramters, you can pass a, b and c after x_init. I think this would work.

Functions with a flexible list of ordered/unordered and labeled/unlabeled inputs in MATLAB

A lot of MATLAB functions have an input structure such as:
output = function MyFun(a,b,c,'-setting1',s1,'-setting2',s2,'-setting3',s3)
I am wondering how I should implement this kind of functionality in my own functions. To be precise, I would like to find out how I can create a function such that:
The function has a variable number of inputs N + M
The first N inputs are ordered and unlabeled. In the example above, N = 3. The first input is always a, second input is always b, third input is always c. The function input is variable in that users do not necessarily need to send b, c; when they do not then these can take on default (hardcoded) values. As far as I know, this type of functionality is generally handled via varargin.
The remaining M inputs are unordered, but labeled. In the example above, M = 3, the variables are s1,s2,s3 and their labels are setting1,setting2 and setting3 respectively, I would like for users to be able to specify these variables in whatever order they want. If users choose not to specify one of these inputs (i.e. setting1), then I would like my function to assign default values for s1.
One example of such a function is the dlmwrite function.
Ideally, I am looking for an approach that is typically used by MATLAB developers so that my code is easy to understand.
The InputParser class addresses all of these issues. You can specify any number of:
Required parameters (ordered, unlabeled)
Optional parameters (ordered, unlabeled)
String parameter-value pairs in any order (unordered, labeled)
A very clear tutorial with examples is provided by MathWorks. For a function defined as function printPhoto(filename,varargin), the example boils down to the following.
Create the inputParser:
p = inputParser;
Specify defaults and define validation criteria:
defaultFinish = 'glossy';
validFinishes = {'glossy','matte'};
checkFinish = #(x) any(validatestring(x,validFinishes));
defaultColor = 'RGB';
validColors = {'RGB','CMYK'};
checkColor = #(x) any(validatestring(x,validColors));
defaultWidth = 6;
defaultHeight = 4;
Define required/optional/parameter input names, set their default values and validation functions:
addRequired(p,'filename',#ischar);
addOptional(p,'finish',defaultFinish,checkFinish);
addOptional(p,'color',defaultColor,checkColor);
addParameter(p,'width',defaultWidth,#isnumeric);
addParameter(p,'height',defaultHeight,#isnumeric);
Parse the inputs into a struct:
parse(p,filename,varargin{:});
Then you have the input arguments and their values in p.Results.
The InputParser class is used throughout newer MathWorks functions, so don't be afraid to use it yourself!