Pass Python function from outside to another function - python

I have a function, which calculate features from my data.
Here is a dummy sample of it
import numpy as np
val1=[1,2,3,4,5,6,7,8,9]
val2=[2,4,6,8,10,12,14,16]
data=[]
def feature_cal(val):
val=np.array(val)
value=val*2
data.append(np.mean(value))
feature_cal(val1)
feature_cal(val2)
What i want is to define the function np.mean() out of my function feature_cal.
Pseudo code
def feature_cal(val,method):
val=np.array(val)
value=val*2
data.append(method(value))
feature_cal(val1,method=np.mean())
feature_cal(val2,method=np.mean())
This will help me to calculate other features such as np.std(), np.var() without changing the original function

To pass the function you need to remove the parentheses after np.mean:
import numpy as np
def feature_cal(val, method):
val = np.array(val)
value = val*2
data.append(method(value))
feature_cal(val1, method=np.mean)
feature_cal(val2, method=np.mean)
EDIT
If you need to pass arguments to np.mean you can use functools.partial:
import numpy as np
import functools
def feature_cal(val, method):
val = np.array(val)
value = val*2
data.append(method(value))
bound_function = functools.partial(np.mean, axis=1)
feature_cal(val1, method=bound_function)
feature_cal(val2, method=bound_function)

If I got you correctly you need to pass callable and not result of function invocation as you do now. So this line
feature_cal(val1,method=np.mean())
Shouls read
feature_cal(val1,method=np.mean)

You can simply insert a method as a parameter into a function by entering the name of the method (without parentheses) and by reading the function you will call(with parentheses) the inserted parameter
def feature_cal(val,method):
val=np.array(val)
value=val*2
data.append(method(value))
feature_cal(val1,method=np.mean)

Related

The more pythonic way to call more than one function [duplicate]

In Python we can assign a function to a variable. For example, the math.sine function:
sin = math.sin
rad = math.radians
print sin(rad(my_number_in_degrees))
Is there any easy way of assigning multiple functions (ie, a function of a function) to a variable? For example:
sin = math.sin(math.radians) # I cannot use this with brackets
print sin (my_number_in_degrees)
Just create a wrapper function:
def sin_rad(degrees):
return math.sin(math.radians(degrees))
Call your wrapper function as normal:
print sin_rad(my_number_in_degrees)
I think what the author wants is some form of functional chaining. In general, this is difficult, but may be possible for functions that
take a single argument,
return a single value,
the return values for the previous function in the list is of the same type as that of the input type of the next function is the list
Let us say that there is a list of functions that we need to chain, off of which take a single argument, and return a single argument. Also, the types are consistent. Something like this ...
functions = [np.sin, np.cos, np.abs]
Would it be possible to write a general function that chains all of these together? Well, we can use reduce although, Guido doesn't particularly like the map, reduce implementations and was about to take them out ...
Something like this ...
>>> reduce(lambda m, n: n(m), functions, 3)
0.99005908575986534
Now how do we create a function that does this? Well, just create a function that takes a value and returns a function:
import numpy as np
def chainFunctions(functions):
def innerFunction(y):
return reduce(lambda m, n: n(m), functions, y)
return innerFunction
if __name__ == '__main__':
functions = [np.sin, np.cos, np.abs]
ch = chainFunctions( functions )
print ch(3)
You could write a helper function to perform the function composition for you and use it to create the kind of variable you want. Some nice features are that it can combine a variable number of functions together that each accept a variable number of arguments.
import math
try:
reduce
except NameError: # Python 3
from functools import reduce
def compose(*funcs):
""" Compose a group of functions (f(g(h(...)))) into a single composite func. """
return reduce(lambda f, g: lambda *args, **kwargs: f(g(*args, **kwargs)), funcs)
sindeg = compose(math.sin, math.radians)
print(sindeg(90)) # -> 1.0

Python function default argument random value

In the following code, a random value is generated as expected:
import random
for i in range(10):
print(random.randint(0,10))
However, this does not work if I use a function:
import random
def f(val: int = random.randint(0,10)):
print(val)
for i in range(10):
f()
Why is the result of the second code snippet always the same number? The most similar question I could find is this one, but it refers to a different language (I don't master) .
The default argument expression isn't evaluated when you call the function, it's evaluated when you create the function. So you'll always get the same value no matter what you do.
The typical way around this is to use a flag value and replace it inside the body of the function:
def f(val=None):
if val is None:
val = random.randint(0,10)
print(val)
You'll want to have the default value be a specific value. To make it be dynamic like that, you'll want to default it to something else, check for that, and then change the value.
For example:
import random
def f(val=None):
if val is None:
val = random.randint(0,10)
print(val)
for i in range(10):
f()
The default param can't be changed on calling.
I can't understand why it needed.
you can do simply like this.
import random
def f():
print(random.randint(0,10))
for i in range(10):
f()

TypeError: processingTime() missing 1 required positional argument: 'num_job'

I try to convert these code below to script:
import pandas as pd
import numpy as np
num_job=10 # number of jobs
pt_tmp=pd.read_excel("JSP_dataset.xlsx",sheet_name="Processing Time",index_col =[0])
pt=[list(map(int, pt_tmp.iloc[i])) for i in range(num_job)]
to ExcelReadFile.py
import pandas as pd
class ExcelReadFile(object):
def __init__(self,fileName, num_job):
self.fileName = fileName
self.num_job = num_job
def processingTime(self, fileName, num_job):
pt_tmp=pd.read_excel(fileName,sheet_name="Processing Time", index_col =[0])
pt=[list(pt_tmp.iloc[i]) for i in range(num_job)]
return pt
and in run.py
import pandas as pd
import numpy as np
import time
from src.fjsls.io.ExcelReadFile import ExcelReadFile
num_job=10
fileName = "JSP_dataset.xlsx"
pt = ExcelReadFile.processingTime(fileName, num_job)
it shows
`TypeError: processingTime() missing 1 required positional argument:
'num_job'
when i call processingTime()
Could you please help to check and a little explanation about script creation in Python?
The reason to this error is you have not create instance of the class .
Do this
import pandas as pd
import numpy as np
import time
from src.fjsls.io.ExcelReadFile import ExcelReadFile
num_job=10
fileName = "JSP_dataset.xlsx"
e = ExcelReadFile(fileName, num_job)
pt = e.processingTime(fileName, num_job)
OR if you want to use this method directly use static method . This method are directly called by class name.
How that is use you can see this link
Static methods in Python?
You're invoking the method on the class, but it's an instance method. Make the method static and then it should work, like this:
#staticmethod
def processingTime(fileName, num_job): # Note that the "self" param is removed
...
you are calling a function from a class:
you are calling it like
pt = ExcelReadFile.processingTime(fileName, num_job)
change this line to
obj=ExcelReadFile(fileName, num_job)
obj.processingTime(fileName, num_job)# at this line you will get the current
# object value in the self
also, your question indentation is mistaken I edit it, please check it and accept the edit if that's right? then only we can understand it correctly.

Currying in inversed order in python

Suppose I have a function like this:
from toolz.curried import *
#curry
def foo(x, y):
print(x, y)
Then I can call:
foo(1,2)
foo(1)(2)
Both return the same as expected.
However, I would like to do something like this:
#curry.inverse # hypothetical
def bar(*args, last):
print(*args, last)
bar(1,2,3)(last)
The idea behind this is that I would like to pre-configure a function and then put it in a pipe like this:
pipe(data,
f1, # another function
bar(1,2,3) # unknown number of arguments
)
Then, bar(1,2,3)(data) would be called as a part of the pipe. However, I don't know how to do this. Any ideas? Thank you very much!
Edit:
A more illustrative example was asked for. Thus, here it comes:
import pandas as pd
from toolz.curried import *
df = pd.DataFrame(data)
def filter_columns(*args, df):
return df[[*args]]
pipe(df,
transformation_1,
transformation_2,
filter_columns("date", "temperature")
)
As you can see, the DataFrame is piped through the functions, and filter_columns is one of them. However, the function is pre-configured and returns a function that only takes a DataFrame, similar to a decorator. The same behaviour could be achieved with this:
def filter_columns(*args):
def f(df):
return df[[*args]]
return f
However, I would always have to run two calls then, e.g. filter_columns()(df), and that is what I would like to avoid.
well I am unfamiliar with toolz module, but it looks like there is no easy way of curry a function with arbitrary number of arguments, so lets try something else.
First as a alternative to
def filter_columns(*args):
def f(df):
return df[*args]
return f
(and by the way, df[*args] is a syntax error )
to avoid filter_columns()(data) you can just grab the last element in args and use the slice notation to grab everything else, for example
def filter_columns(*argv):
df, columns = argv[-1], argv[:-1]
return df[columns]
And use as filter_columns(df), filter_columns("date", "temperature", df), etc.
And then use functools.partial to construct your new, well partially applied, filter to build your pipe like for example
from functools import partial
from toolz.curried import pipe # always be explicit with your import, the last thing you want is import something you don't want to, that overwrite something else you use
pipe(df,
transformation_1,
transformation_2,
partial(filter_columns, "date", "temperature")
)

scipy -- how to convert a function result to array

Hello i have the function Walk1d which then i want to calculate the cumsum.
I use Walk1d=lambda n: sc.cumsum(steps(n)) .The result is an array but when i am trying Walk1d.cumsum() it doesn't work because type(Walk1d) is a function.
If i try sc.array(Walk1d).cumsum() it gives me : at 0x3798488>
How can i handle this?
import matplotlib.pyplot as plt
import scipy as sc
steps=lambda m: 2*sc.random.random_integers(0,1,size=m)-1
Walk1d=lambda n: sc.cumsum(steps(n))
print(sc.array(Walk1d).cumsum())
Thanks!
Walk1d is a function taking an argument. You have to call the function and pass in an argument to get a result, for example
print(Walk1d(10).cumsum())
The function Walk1d needs to be called with a parameter n:
print(sc.array(Walk1d(10)).cumsum())

Categories