Declaring a function in a parameter list in python - python

I'm looking to build a generic object for curve fitting, where I define parameter names, values and bounds. Sometimes, I want to use the incoming data to help define the bounds using a function (min, max, etc.).
Here is the object:
class CurveFitObject(object):
def __init__(self,paramList,growthEquation):
self.paramList = paramList
self.gmod = Model(growthEquation)
def calcCurveFit(data):
for param in self.paramList:
self.gmod.set_param_hint(self.paramList['name'],
value=self.paramList['value'](data),
min=self.paramList['min'](data),
max=self.paramList['max'](data))
Here I am trying to use np.min(data) as my guess, 0.975 * np.min(data) as my lower bound, and 1.025 * np.min(data) as my upper bound.
def growthEquation(self, t, A): return A
keys = ['name','guess','min','max','vary']
logisticGrowth = CurveFitObject(
[dict(zip(keys,['A',np.min,0.975*np.min,1.025*np.min,True])),
growthEquation
)
I get the following error: TypeError: unsupported operand type(s) for *: 'float' and 'function'
which makes sense since it's trying to do math on the function 0.975*np.min rather than 0.975*np.min(data).
What is the best way to implement this behavior? If any?

It looks like you want to create a wrapper for an existing function. For example, you have:
0.975*np.min
But this doesn't work, since it's trying to multiply a float times a function. You can create a new function inline by using:
lambda data: 0.957*np.min(data)
This is probably what you're looking for. It's equivalent to defining a named function:
def myfunc(data):
return 0.957*np.min(data)
and then using myfunc. The difference is that the lambda syntax creates an anonymous function that can be defined inline.

Related

TypeError: Mean() missing 1 required positional argument: 'data'

I'm trying to program a basic mean calculator using classes. However, I'm getting the error
TypeError: Mean() missing 1 required positional argument: 'data'
I have two files: one which contains the class with the mean function and then one which calls it, and that is when I'm getting the error. My code is:
class Statistics:
def __init__(self,mean_x,mean_y,var,covar):
self.mean_x=mean_x
self.mean_y=mean_y
self.var=var
self.covar=covar
def Mean(self,data):
return sum(data)/float(len(data))
And the code which throws the error is:
from Statistics import Statistics
X=(0,1,3,5)
mean_x=Statistics.Mean(X)
print(mean_x)
Mean is an instance method, so you need to call it on an instance (which will become the self argument for the method invocation).
statistics = Statistics(None, None, None, None)
mean_x = statistics.Mean((0, 1, 3, 5))
Since the parameters on Statistics.__init__ aren't used I'd suggest removing them (or just removing the __init__ altogether):
class Statistics:
def mean(self, data):
return sum(data)/float(len(data))
from Statistics import Statistics
X = (0,1,3,5)
statistics = Statistics()
mean_x = statistics.mean(X)
print(mean_x)
Note that Python comes with a statistics module that has a mean function built in:
import statistics
X = (0,1,3,5)
mean_x = statistics.mean(X)
print(mean_x)
You define the instance method, but there is no instance.
Also, it is better to change the 'Mean' to 'mean'.

How to define a function that returns the derivative to be later passed in a lambda function

Consider the following Python code
def Hubble_a(a):
...
return
def t_of_a(a):
res = np.zeros_like(a)
for i,ai in enumerate(a):
t,err = quad(lambda ap : 1.0/(ap*Hubble_a(ap)),0,ai)
res[i] = t
return res
a = np.logspace(-8,1,100)
What I want to do is to define a function Hubble_a(a) that gives the derivative of a divided by a, in order to integrate over it with quad. I tried to define it in this way:
def Hubble_a(a):
da = diff(a,1)
da_over_a = da/a
return da_over_a
where diff is the FFT derivative imported from scipy.fftpack. Then, if I execute t_of_a(a) I get a object of type 'float' has no len() error, presumably because quad doesn't take arrays? However I don't think this definition makes any sense in the first place because I want to pass a function such that lambda maps to 1.0/(ap*Hubble_a(ap) and know I'm passing the derivative of an array instead of a function that can then by integrated over. So I'm looking for help on how to implement a function that maps to something like (da/dt)/a.

Numpy exp() not callable

If I use 2 np arrays as x,y input into the following expression...
out = np.exp(3(x-4)-0.0001*y)
...I get "TypeError: 'int' object is not callable
If I use the same as function and call this function with a curve fit I get a similiar error:
def func(X, a, b):
x,y = X
return np.exp(a(x-4)-b*y)
Here I get:'numpy.float64' object is not callable
What am I doing wrong? It's working with others type of functions that don't use exp.
out = np.exp(3(x-4)-0.0001*y)
The problem in this expression is that the np.exp() function takes one argument but you passed 2. I don't know this is the best solution but instead of this you can try:
operations = 3*(x-4) - (0.0001*y)
out = np.exp(operations)

Python function that takes two functions and returns the concatenated function?

I need to write a python function called 'concat' that takes any two functions as input, and returns a function, which is the concatenated function of the two input functions (i.e. it takes f1 and f2, and returns f1◦f2).
I tried this:
def concat(f1,f2):
return f1(f2)
So for example, if f1 and f2 are:
def f1(x):
return x+2
def f2(x):
return x*2
then, concat(f1,f2) should return: (x*2)+2
I want to be able to use it like this:
a = concat(f1,f2)
a(5)
But I get an error:
TypeError: unsupported operand type(s) for +: 'function' and 'int'
I know I can define the function like this:
def concat(f1,f2,x):
return f1(f2(x))
But that is not what I want; I want to be able to create instances of the concat function, which then can be called with any x.
You need to return a new "wrapper" function. One option is to use a lambda expression:
def concat(f1, f2):
return lambda x: f1(f2(x))
DOCS: https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions
I think what you want is a closure.
def concat(f1, f2):
def f3(x):
return f1(f2(x))
return f3
Functions in Python are considered first class objects. This allows them to be created and manipulated like normal variables. In this case concat is constructing a new function that composes two functions.
The second property being used here is lexical scoping. The new function retains access to the local variables where it was defined not where it is executed. This allows the returned function to be run anywhere without losing access to the composite functions.
Here's a possible solution to compose more than two functions. Using a closure to loop through the functions and use the previous function's result as argument for the next one:
def compose(*fns):
def F(x):
for fn in fns[::-1]:
x = fn(x)
return x
return F
Then define your composition and call:
>>> F = compose(f1, f2, lambda x: x+1)
>>> F(4)
12 # f1(f2(f3(x)))

negative function in python

I have a function defined that calculates the minimum of a function like x^2. I want to define a function that would calculate the maximum of a function by calculating the minimum of a similar function by multiplying through by negative one.
def myf(g):
return -(g+1.3)**2+5
def maximize(f,low,high,tol):
return minimize(-1*f,low,high,tol)
Is there a way to do this? When I try what I have I get the following error:
TypeError: unsupported operand type(s) for *: 'int' and 'function'
minimize is defined as such:
def minimize(f,low,high, tol):
if low>high:
c=low; a=high
a=float(a); c=float(c);
else:
a=float(low); c=float(high);
b=a+(c-a)*.618033
fa=f(a); fc=f(c)
fb=f(b);
if fb>fa or fb>fc: return maximize(f,low,high,tol)
while abs(a-c)>tol:
d=a+(c-b);
fd=f(d);
if d<b:
if fb<fd:
a=d; fa=fd;
else:
c=b; b=d
fc=fb; fb=fd
else:
if fd<fb:
a=b; fa=fb;
b=d; fb=fd
else:
c=d; fc=fd
return (a+c)/2.
Looking for a python code only solution.
You can't multiply a function with a number. Instead, construct a new function that uses the old one and multiplies the result (and not the function itself) with a number:
def maximize(f,low,high,tol):
return minimize(lambda x: -f(x),low,high,tol)
There are several ways to do this. The most straightforward is to "wrap" your function into another function. You can use lambda: new_f = lambda x: -f(x). In case you are not familiar with lambda's, this is a shortcut for
def new_f(x):
return -f(x)
Maybe you should be using scipy.optimize?
http://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html

Categories