Python: how to evaluate a function that is a string?

I am getting some models from the database as

f(t)=(2.128795454425367)+(208.54359721863273)*t+(26.098128487929266)*t^2+(3.34369909584111)*t^3+(-0.3450228278737971)*t^4+(-0.018630757967458885)*t^5+(0.0015029038553239819)*t^6;

      

which is like a string.

I need to evaluate this function for t in range(1, 13)

Now I have to manually copy these functions and run them

   print [1.2381648958643592 + \
          153.55656654019816 * t +\
          22.99318731025164 * (t**2) +\
          11.060577906796075 * (t**3) +\
          -1.3465054084767891 * (t**4) + \
          0.016926765998876842 * (t**5) +\
          0.001500086893490721 * (t**6) for t in range(1, 13)]

      

Is there a better way to do this in python?

0


source to share


5 answers


If performance is not a major issue, and if you're only evaluating it at 12 points, I suspect it isn't - then you can use the handy sympy to do most of the work for you. For example:

>>> import sympy
>>> sympy.sympify("t**5 - t + 3")
t**5 - t + 3
>>> sympy.sympify("t**5 - t + 3").subs({"t": 10})
99993

      

We can wrap this in a function that returns a function:



import sympy

def definition_to_function(s):
    lhs, rhs = s.split("=", 1)
    rhs = rhs.rstrip('; ')
    args = sympy.sympify(lhs).args
    f = sympy.sympify(rhs)
    def f_func(*passed_args):
        argdict = dict(zip(args, passed_args))
        result = f.subs(argdict)
        return float(result)
    return f_func

      

which we can apply, even in more complex cases that are not available to a regular expression:

>>> s = "f(t)=(2.128795454425367)+(208.54359721863273)*t+(26.098128487929266)*t^2+(3.34369909584111)*t^3+(-0.3450228278737971)*t^4+(-0.018630757967458885)*t^5+(0.0015029038553239819)*t^6;"
>>> f = definition_to_function(s)
>>> f(0)
2.128795454425367
>>> f(10)
4230.6764921149115
>>> f = definition_to_function("f(a,b,c) = sin(a)+3*b-4*c")
>>> f(1,2,3)
-5.158529015192103
>>> import math
>>> math.sin(1)+3*2-4*3
-5.158529015192103

      

+1


source


If you want to parse the "function" string, you can do something like this:

import re

s = "f(t)=(2.128795454425367)+(208.54359721863273)*t+(26.098128487929266)*t^2\
    +(3.34369909584111)*t^3+(-0.3450228278737971)*t^4+(-0.018630757967458885)*t^5\
    +(0.0015029038553239819)*t^6;"

def f(t):
    l = map(float, re.findall("-?\\d+\\.\\d+", s))
    return sum(b * t**a for a,b in enumerate(l))

print map(f, xrange(1,13))

      

[239.75206957484252, 544.337732955938, 921.544112756058, 1366.6221363666925, 1864.8848673959649, 2393.2591324279497, 2922.9192385578326, 3423.0027817028927, 3865.40859389


This approach assumes that the function string will always be

c0 + c1 t + c2 t ^ 2 + c3 t ^ 4 + ... cn t ^ (n + 1)

and works by extracting floating point numbers from a string and using them to create a real Python function.

0


source


You can store this function as a python expansion in your database, and when you get the string, just do something like eval (funcstr.replace ('x', 'yvalue')).

To show you an example:

funcstr = '2*x+5'
evalpoint = funcstr.replace('x', '5')
val = eval(funcstr)

      

At this point, val should be evaluated to 15

0


source


As NPE says, the correct answer here is to write a parser (and a simple interpreter) for your expression language.

Or, better yet, if at all possible, first generate the expressions in Python rather than in a language that is almost, but not entirely, compatible with a subset of Python.

Or, even better, if a language is just a way of representing a list of coefficients for a polynomial, just think of it as a list of coefficients that is much easier to parse than any real general-purpose language. For example, suppose the following was specified in the database:

2.128795454425367, 208.54359721863273, 26.098128487929266, 3.34369909584111, -0.3450228278737971, -0.018630757967458885, 0.0015029038553239819

      

Then, to accomplish this in Python, you would do the following:

def eval_polynomial(polynomial, value):
    coefficients = [float(x.strip()) for x in polynomial.split(',')]
    return sum(coefficient * (value**exponent) 
               for exponent, coefficient in enumerate(coefficients))

      

Then:

>>> [eval_polynomial(expr, t) for t in range(1, 13)]

      

But if you really want to do it without changing what's in the database, you can simply convert it to a Python expression and evaluate it:

>>> expr = 'f(t)=(2.128795454425367)+(208.54359721863273)*t+(26.098128487929266)*t^2+(3.34369909584111)*t^3+(-0.3450228278737971)*t^4+(-0.018630757967458885)*t^5+(0.0015029038553239819)*t^6;'
>>> removef = re.sub(r'f\((\w+)\)=', 'lambda \1: ', expr)
>>> fixpower = re.sub(r'(\w+)\^(\d+)', r'(\1**\2)', removef)
>>> nosemi = fixpower.replace(';', '')
>>> func = eval(nosemi)
>>> [func(t) for t in range(1, 13)]
[239.75206957484252, 544.337732955938, 921.544112756058, 1366.6221363666925, 1864.8848673959649, 2393.2591324279497, 2922.9192385578326, 3423.0027817028927, 3865.4085456893295, 4230.676492114911, 4514.949840987468, 4738.019242139209]

      

But you probably don't want to do this.

And if you do, you probably want to write a transformer that works in your actual language, rather than guessing in your language based on one example ...

0


source


if you trust your sources you can do it with regex and eval:

# deletes the simicolon and everything before the space
my_str = start_str.split('=')[1][:-1]
# change ^ to ** because that the squared operator
my_str = re.sub('\^', '**', my_str)
# substitute the t for the numbers 1 to 13 and evaluate the string
results = [eval(re.sub('t', str(t), my_str)) for t in range(1,13)]

      

0


source







All Articles