I have two numpy matrices. One contains lambda functions. The other contains values.
Is there a function that is similar to Python's map function that will allow me to get the expected result?
Is there a better way?
functionMatrix = np.array([[lambda x:x**2, lambda x:x**3],[lambda x: x**2,
lambda x: np.sqrt(x)]])
valueMatrix = np.array([[1,2],[3,4]])
expectedResult = np.array([[1,8],[9,2]])
This is just syntactic sugar but does the job.
#np.vectorize
def apply_vec(f, x):
return f(x)
result = apply_vec(functionMatrix, valueMatrix)
Related
I have a pipeline function that takes an arbitrary number of functions as arguments, it returns a single function helper which contain one argument and this function in turn calls the pipeline function with a single argument iteratively. Here is the code:
def pipeline(*funcs):
def helper(arg):
for func in funcs:
result = func(arg)
arg = result
return result
return helper
And here a test case:
fun = pipeline(lambda x: x * 3, lambda x: x + 1, lambda x: x / 2)
print(fun(3)) #should print 5.0
I was reading on a different question about generators and how they can be used to remember previous state here, and was wondering if I could reframe my current pipeline function to use a generator instead. I need to remember the arg for every func call and currently I'm doing that by storing into a variable, however since generators can remember the last state I was wondering if I could use it instead.
You could (but absolutely shouldn't) create a side-effect based list-comprehension that uses the walrus-operator:
funcs = [lambda x: x * 3, lambda x: x + 1, lambda x: x / 2]
x = 3
[x := f(x) for f in funcs]
print(x)
What makes this even worse than it already is is the fact that if you use a simple generator instead of the list-comprehension the result is different because it doesn't all get executed before the print.
Or you even force it all in one line like this:
print([x := f(x if i>0 else 3) for i, f in enumerate(funcs)][-1])
I think generally a prettier approach would be to just wrap it into a normal for loop:
x = 3
for f in funcs:
x = f(x)
print(x)
Edited the Question for Clarification
import numpy as np
tt = np.arange(0, 1000, 1)
st = np.arange(0, 10, 1)
def abc():
return lambda x: st[np.where(tt==x)] if (50 < x <100) else 0
print(abc()(tt))
Expectation is that for a given, long periodic time-series tt with a period of 100, the function abc() should output the values in st for the interval 50-100, 150-200, 250-300, and spit out 0 elsewhere. Something like..
[0....0..st.....st.0.....0.st....st.0....0.st.....st]
Previously asked....
I inherited a long code to which I need to do some modification. The basic format is a number of functions, each returning a lambda function
def func1():
return lambda x: #some math with x, like x**2
def func2():
return lambda x: #some math with x, like np.sin(x)
and so on..
These functions are supplied with a time-series, t, a numpy 1D array from which the required math function is generated. It works properly.
For instance
import numpy as np
import matplotlib.pyplot as plt
t = np.arange(0, 100, 1)
def fun1():
return lambda x: x**2
print(fun1()(t))
plt.plot(t, fun1()(t))
plt.savefig('Graph.png')
Now I wish to import/read data from an external file as a [time, value] pair and use that to generate the new math function, instead of doing math in the function itself as before.
After reading from a file, I have say,
time = [0, 0.1, 0.2, ..... 1000.0]
value = [v1, v2, ...........vn]
I want to do
def new_func():
return lambda x: "*Looking for an answer*"
So that if I call new_func()(t), I get the value as the output
I have tried np.where, and tried defining subfuctions. But nothing has worked so far. Because I have to pass this function to another code, I can't change the basic format. Please advise.
lambda is a function by itself. Putting it into a def formal function as the sole output make no sense.
If you want to multiply by 2 for an entire list, lambda will not be enough, you'll also need an iterator. The following:
func = lambda x: x*2
Simply means this is an lambda function that will return input*2, it is equivalent to:
def func(x): return x*2
If you want to make it apply to an entire list, you'll need to do:
list(map(lambda x: x*2, mylist))
map will map the function to each element of the list, but that will also work for a named function.
In order to make your purpose, assuming both value and time are list of same length.
lambda t: value[time.index(t)]
is the function you need. Call it like this:
(lambda t: value[time.index(t)])(t)
# OR:
func = lambda t: value[time.index(t)] # assign it name and then
func(t)
Is there a way in numpy to have a vector of n different functions that all take one input x and then "map" this vector to another vector where the functions have been replaced by the functions evaluated at x? For example:
funcs = np.array[lambda x: 2*x for i in range(2)]
x = np.array([10,20])
y = np.evaluate_all(funcs, x)
print(y) # [20,40]
Well, there is a (mostly) pure Python way using zip:
def evaluate_all(funcs, x):
return np.array([func(val) for func, val in zip(funcs, x)])
A way to use a bit more numpy, would be using the numpy.vectorize wrapper, which allows you to use the numpy broadcasting rules (which simplify here to call the function once for each pair of items in funcs and x):
#np.vectorize
def evaluate_all(f, x):
return f(x)
y = evaluate_all(funcs, x)
This has the nice feature that it also allows you to do e.g. evaluate_all(funcs, 10) (so funcs has some length, but x is just a scalar), or evaluate_all(lambda x: 2*x, [10, 20]) (which is the same as apply, but probably slower).
Note, though that the documentation for numpy.vectorize states:
The vectorize function is provided primarily for convenience, not for
performance. The implementation is essentially a for loop.
The two functions differ in their behavior in the case where funcs and x are not of the same dimension. zip just stops at the end of the shorter iterable, while numpy will raise a ValueError if the shapes are incompatible.
using Pandas series and apply :
funcs = np.array([lambda x: 2*x for i in range(2)])
x = np.array([10,20])
y = pd.Series(x).apply([x for x in funcs]).values[:,0 ]
print(y) # [20,40]
Without List comprehension as suggest in comments :
y = pd.Series(x).apply(list(funcs)).values[:,0 ]
print(y) # [20,40]
I'm trying to write a function in Python for a polynomial p that is a linear combination of n basis functions phi_i. How can I define a function that is itself a sum of n other functions?
I know that this works:
phi1 = lambda x: x**2
phi2 = lambda x: x
p = lambda x: phi1(x) + phi2(x)
But if I try a loop like this:
p = lambda x: 0
for i in range(0,n):
p = lambda x: p(x)+phi[i](x)
where phi is a list of my basis functions, I create an infinite loop.
I checked Writing a function that is sum of functions, but unfortunately that's not in Python.
You can do this by passing a simple generator expression to sum:
def sigma(funcs, x):
return sum(f(x) for f in funcs)
phi = [lambda x: x**2, lambda x: x]
y = sigma(phi, x)
BTW, it's considered bad style to use lambda for named functions, it's supposed to be for anonymous functions.
If you want a function that doesn't need phi to be passed in each time you call it, there are a couple of ways to do that. The easiest way is to simply use phi in the function. Eg,
def sigma(x):
return sum(f(x) for f in phi)
However, that has a couple of downsides. It won't work if phi isn't in the scope where you call sigma; you can get around that by making phi global, but that may not be convenient, and it's best to avoid globals when they aren't necessary. The other downside is that it uses the current contents of phi, not the contents it had when sigma was defined, so if you modify the contents of phi those changes will be reflected in sigma, which may or may not be desirable.
Another option is to use a closure to create the function. Then we won't be affected by the scope issue: you can call the resulting summing function inside a scope where the original function list isn't visible. We can also create a copy of the function list, so it won't be affected by changes to the passed-in function list.
def make_adder(funcs):
# Copy the function list
funcs = funcs[:]
def sigma(x):
return sum(f(x) for f in funcs)
return sigma
phi = [lambda x: x**2, lambda x: x]
sigma = make_adder(phi)
y = sigma(x)
Yet another option is to use my original sigma and pass it and the phi functions to functools.partial, eg
from functools import partial
sig = partial(sigma, phi)
y = sig(x)
Straight answer to OP
Store your phis in a list:
phis = [
lambda x: x**2,
lambda x: x,
]
p = lambda x: sum(phi(x) for phi in phis)
Further considerations
If you want to achieve a polynomial, I would suggest something similar to this:
def poly(c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
poly function accepts a sequence as the only argument, where its elements need to be int or float. The first element is assigned as the coeficient of x^0, the second to x^1 and so on. So your example (p(x) = x + x^2) would end up being constructed like this: p = poly([0, 1, 1])
Another option is to accept any number of arguments where each of them needs to be a int or float instead of the first being a sequence. This would only require to add one * to the function declaration.
def poly(*c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
To construct your example with this function you would not require the list: p = poly(0, 1, 1).
Any of those methods would create a polynomic function that can be called as you would expect: p(1) would return 2, p(2) would return 6 and so on.
Function explained
def poly(c):
# Create a list where we are gonna store the functions for every term in the polynomial
terms = []
# Create as many terms as the arguments length
for i in range(len(c)):
# Each term is the product of the nth coefficient from c and x to the power of n
terms.append(lambda x, n=i: c[n]*x**n)
# The second parameter n is needed because if we pass i directly
# inside the function algorithm, Python wouldn't check its value
# inmediately, but when it gets executed, and by then the loop will
# be finished and i would be constant for every term. This argument
# is not exposed to the polynomial function as the next lambda only
# has one argument, so there is no way to wrongly call this function
# We return a function that adds the result of every term
return lambda x: sum(f(x) for f in terms)
As an input, I have a list of nonnegative whole numbers which are supposed to be the coefficients of a polynomial. But I also want to evaluate the polynomial for a certain number x.
For example:
If we have L=[2,3,1] as an input and x=42 we get 2x^2+3x+1=3655
What I want is for example:
>>>p=polynomial([2,3,1])
>>>p(O)
1
>>>p(42)
>>>3655
I guess I have to make use of the lambda function somehow, and I do know how it works for two variables on a given function, but in this case the function depends on my input.
def polynomial(coef):
coef=coef[::-1]
for i in range(len(coef)):
p=lambda x: coef[i]*x**i
p+=p
return lambda x: p
This is of course absolute nonsense, as I cannot add up one lambda function to another, but this is what my approaching "intuition" is.
Some hints are much appreciated.
The most obvious pythonic solution (using a closure - with a lambda or (preferably) a named inner function) has already been posted, but for the sake of completeness I'll add the other pythonic solution - the OO version using a custom callable class:
class Polynomial(object):
def __init__(self, coef):
self.coef = coef
def __call__(self, x):
n = len(self.coef) - 1
return sum(c * x ** (n - i) for (i, c) in enumerate(self.coef))
p = Polynomial([2,3,1])
print p(0)
print p(42)
Simple Python:
def make_poly(coefs):
def poly(x):
result = 0
for c in coefs:
result = result * x + c
return result
return poly
p = make_poly([2,3,1])
print(p(0))
print(p(42))
EDIT: code modified as suggested by Mark Dickinson in the comments
You can do it using lambda:
def polynomial(coef):
n = len(coef) - 1
return lambda x : sum([c * x ** (n - i) for (i, c) in enumerate(coef)])
Lambda isn't necessary however, you can define another function inside the polynomial function like so:
def polynomial(coef):
def f(x):
n = len(coef) - 1
return sum([c * x ** (n - i) for (i, c) in enumerate(coef)])
return f
Edit: Previously input was tied to 3 coefficients
The following lambda function evaluates a polynomial function, input as a coeff list of coefficients, in a given x:
from functools import reduce
lambda coeff, x: reduce(lambda a, b: a*x + b, coeff)
It seems that you want to generate these polynomial functions. You can still do it with this method:
def generate_polynomial(coeff):
return lambda x: (lambda y: reduce(lambda a, b: a*y + b, coeff))(x)
>>> p = generate_polynomial([20,0,17])
>>> p(10)
2017
This is merely based on Horner's algorithm.
Besides, if you want to use exclusively lambda and no built-in functions, you can also emulate reduce with lambda functions. You might want to give a look at Python - Removing duplicates in list only by using filter and lambda and Removing duplicates using only lambda functions, showing how to get rid of the filter function.