I have problem implementing residuals function for leastsq optimization of scipy when importing it from another file - scipy

I have written a code in which functions are called in each other. The working code is as follows:
import numpy as np
from scipy.optimize import leastsq
import RF
func = RF.roots
# residuals = RF.residuals
def residuals(params, x, y):
return y - func(params, x)
def estimation(x, y):
p_guess = [1, 2, 0.5, 0]
params, cov, infodict, mesg, ier = leastsq(residuals, p_guess, args=(x, y), full_output=True)
return params
x = np.array([2.78e-03, 3.09e-03, 3.25e-03, 3.38e-03, 3.74e-03, 4.42e-03, 4.45e-03, 4.75e-03, 8.05e-03, 1.03e-02, 1.30e-02])
y = np.array([2.16e+02, 2.50e+02, 3.60e+02, 4.48e+02, 5.60e+02, 8.64e+02, 9.00e+02, 1.00e+03, 2.00e+03, 3.00e+03, 4.00e+03])
FIT_params = estimation(x, y)
print(FIT_params)
where RF file is:
def roots(params, x):
a, b, c, d = params
y = a * (b * x) ** c + d
return y
def residuals(params, x, y):
return y - func(params, x)
I would like to remove residuals function from the main code and use it by calling from RF file instead i.e. by activating the code line residuals = RF.residuals. By doing so, error NameError: name 'func' is not defined will be appeared. I put func argument in RF's residuals function as def residuals(func, params, x, y): which will face to error TypeError: residuals() missing 1 required positional argument: 'y'; It seems the error is related to the forth argument of the residuals function in this sample because it will get error for 'func' if the func argument be placed after the y argument. I couldn't find out the source of the issue, but I guess it must be related to limitation of arguments in functions. I would be appreciated if anyone could guide me to understand the error and its solution.
Is it possible to bring residual function from the main code to the RF file? How?

The problem is that there's no global variable func in your file RF.py, hence it can't be found. A simple solution would be to add an additional parameter to your residuals function:
# RF.py
def roots(params, x):
a, b, c, d = params
y = a * (b * x) ** c + d
return y
def residuals(params, func, x, y):
return y - func(params, x)
Then, you can use it inside your other file like this:
import numpy as np
from scipy.optimize import leastsq
from RF import residuals, roots as func
def estimation(func, x, y):
p_guess = [1, 2, 0.5, 0]
params, cov, infodict, mesg, ier = leastsq(residuals, p_guess, args=(func, x, y), full_output=True)
return params
x = np.array([2.78e-03, 3.09e-03, 3.25e-03, 3.38e-03, 3.74e-03, 4.42e-03, 4.45e-03, 4.75e-03, 8.05e-03, 1.03e-02, 1.30e-02])
y = np.array([2.16e+02, 2.50e+02, 3.60e+02, 4.48e+02, 5.60e+02, 8.64e+02, 9.00e+02, 1.00e+03, 2.00e+03, 3.00e+03, 4.00e+03])
FIT_params = estimation(func, x, y)
print(FIT_params)

Related

Positional argument missing error in scipy optimize

I wanted to get a maximum estimate for the following function in mu and sigma using scipy where s is defined as the sample
s = np.random.normal(mu, sigma, 100)
def f(mu, sigma):
x = norm.pdf(s,mu,sigma)
x = np.prod(x)
x = np.log(x)
return x
I've tried
x0 = [0,1]
bounds = [(-5,5),(-5,5)]
print(optimize.minimize(f, x0, method='SLSQP', bounds=bounds))
but keep getting the error:
f() missing 1 required positional argument: 'sigma'
I'm not sure what's going on here
You need to pass the arguments to f as a vector:
def f(z):
mu, sigma = z
x = norm.pdf(s,mu,sigma)
x = np.prod(x)
x = np.log(x)
return x

Using a function that has another function as parameter:

I want to integrate x^2 from 2 to 4 with the trapezoidal integration method. For this, I defined a function trap that takes 4 arguments:
function y = trap( fn, a, b, h )
n = (b-a)/h;
x = a + [1:n-1]*h;
y = h/2*(feval(fn, a) + feval(fn, b) + 2*sum(feval(fn,x)));
and a function f
function y= f(x)
y=x^2
end
Now, by executing trap(f,2,4,0.1), I get the following error:
Not enough input arguments.
Error in f (line 2)
y=x^2
What is the origin of that error?
You have to call trap using the function handle #f, not f.
trap(#f,2,4,0.1)
function y = trap( fn, a, b, h )
n = (b-a)/h;
x = a + [1:n-1]*h;
y = h/2*(fn(a) + fn(b) + 2*sum(fn(x)));
end
function y= f(x)
y = x.^2;
end
which gives, as expected,
ans =
18.67
Also you needed element-wise multiplication in f(x) to compute y = x.^2.
And feval is not necessary. You can directly call fn(a) to evaluate the function.

Python: Fitting non-linear function into surface

I've got an error gauss function erfc(x) which I need to fit into my data of surface.
Whole equation is:
Z = Z_0 * erfc(x / 2*sqrt(D*t))
I know from data Z, Z_0, x, t ... the only parameter I am looking for is D. Using curve_fit is fine for single lines but I need to find only one constant parameter D for whole surface.
The surface looks like this
].
Any ideas, please? Thanks
I've created an example that demonstrates a multivariate curve_fit. Note that I used a class object to store the parameter Z0, but there are other ways to do this (see this question).
import numpy as np
from scipy.optimize import curve_fit
from scipy.special import erfc
# Class to contain model and parameters
class fitClass:
def __init__(self):
pass
# Model with unknown parameter D
def func(self, p, D):
x, t = p
Z = self.Z0 * erfc(x / 2*np.sqrt(D*t))
return Z
# Instantiate class and define parameters
inst = fitClass()
inst.Z0 = 1.0
D = 10.0
Nx = int(1e2)
Nt = int(1e1)
# Independent variables
x = np.linspace(-1.0, 1.0, Nx)
t = np.linspace(1.0, 5.0, Nt)
X, T = np.meshgrid(x, t)
# Merge independent variables
xdata = np.vstack([X.reshape(-1), T.reshape(-1)])
# Synthetic ydata (noisy measurement)
noise = 0.5*(np.random.rand(Nx*Nt)-0.5)
Z = inst.func(xdata, D)
Z_noisy = Z + noise
# Fit model to data
popt, pcov = curve_fit(inst.func, xdata, Z_noisy)
D_fit = popt[0]
print(D_fit)

Function Overloading Mechanism

class X
class Y extends X
class Z extends Y
class M {
def f(x: X): String = "f with X at M"
def f(x: Y): String = "f with Y at M"
}
class N extends M {
override def f(x: Y): String = "f with Y at N"
def f(x: Z): String = "f with Z at N"
}
val z: Z = new Z
val y: Y = z
val x: X = y
val m: M = new N
println(m.f(x))
// m dynamically matches as type N and sees x as type X thus goes into class M where it calls "f with X at M"
println(m.f(y))
// m dynamically matches as type N and sees y as type Y where it calls "f with Y at N"
println(m.f(z))
// m dynamically matches as type N and sees z as type Z where it calls "f with Z at N"
Consider this code, I don't understand with the final call println(m.f(z)) doesn't behave as I wrote in the comments - is there a good resource for understanding how overloading works in Scala?
Thank!
Firstly overloading in Scala works the same as in Java.
Secondly, it's about static and dynamic binding. Let's find out what compiler see. You have m: M object. Class M has f(X) and f(Y) methods. When you call m.f(z) compiler resolves that method f(Y) should be called because Z is subclass of Y. It's a very important point: compiler doesn't know real class of m object that's why it knows nothing about method N.f(Z). And it's called static binding: compiler resolves method's signature. Later, in runtime, dynamic binding happens. JVM knows real class of m and it calls f(Y) which is overloaded in Z.
Hope my explanations are clearly enough to understand.
class x
class Y extends X
class Z extends Y
class M {
def f(x: X): String = "f with X at M"
def f(x: Y): String = "f with Y at M"
}
class N extends M {
override def f(x: Y): String = "f with Y at N"
def f(x: Z): String = "f with Z at N"
}
val z: Z = new Z
val y: Y = z
val x: X = y
val m: M = new N
println(m.f(x))
// m dynamically matches as type N and sees x as type X thus goes into class M where it calls "f with X at M"
println(m.f(y))
// m dynamically matches as type N and sees y as type Y where it calls "f with Y at N"
println(m.f(z))
// m dynamically matches as type N and sees z as type Z where it calls "f with Z at N"
Because the function will be overloaded on N.so N is depends on m.f(y) .finally it is related with x and y that is reason z function will call
When you do this
val m: M = new N
It means that m is capable of doing everything that class M can. M has two methods - first which can take X, other Y.
And hence when you do this
m.f(z)
Runtime is going to search for a method which can accept z (of type Z). The method in N is not a candidate here because of two reasons
The reference is of type M
Your N does not override any method of M which can accept an argument of type Z. You do have a method in N which can accept a Z but that's not a candidate because it's not overriding anything from M
The best match is f in M which can accept a Y this is because Z ISA Y
You can get what your last comment says if
You define a method in M which takes argument of type Z and then you override it in N
You instantiate a val of type N e.g: val m : N = new N
I think the existing questions on SO already elaborate this point.

In Scipy LeastSq - How to add the penalty term

If the object function is
How to code it in python?
I've already coded the normal one:
import numpy as np
import scipy as sp
from scipy.optimize import leastsq
import pylab as pl
m = 9 #the degree of the polynomial
def real_func(x):
return np.sin(2*np.pi*x) #sin(2 pi x)
def fake_func(p, x):
f = np.poly1d(p) #polynomial
return f(x)
def residuals(p, y, x):
return y - fake_func(p, x)
#randomly choose 9 points as x
x = np.linspace(0, 1, 9)
x_show = np.linspace(0, 1, 1000)
y0 = real_func(x)
#add normalize noise
y1 = [np.random.normal(0, 0.1) + y for y in y0]
p0 = np.random.randn(m)
plsq = leastsq(residuals, p0, args=(y1, x))
print 'Fitting Parameters :', plsq[0]
pl.plot(x_show, real_func(x_show), label='real')
pl.plot(x_show, fake_func(plsq[0], x_show), label='fitted curve')
pl.plot(x, y1, 'bo', label='with noise')
pl.legend()
pl.show()
Since the penalization term is also just quadratic, you could just stack it together with thesquares of the error and use weights 1 for data and lambda for the penalization rows.
scipy.optimize.curvefit does weighted least squares, if you don't want to code it yourself.