2012-12-05 41 views
0

我從數據庫中獲取某些型號爲Python:如何評估一個函數是字符串?

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; 

其作爲薩姆字符串。

我現在需要我必須手動複製這些功能和運行它們

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)] 

有沒有更好的辦法做到這一點在Python來評估此功能t in range(1, 13)

+6

如果表達式是在Python中,那麼您可以使用一些快捷方式。但是,由於它們的語言不同,所以適當的解決方案將涉及爲其他語言創建解析器。 – NPE

+1

您可以使用正則表達式解析它或使用'eval',但後者在這種情況下也需要一些預處理。 –

+2

如何生成模型?有沒有辦法將它們生成爲Python代碼而不是其他語言? – abarnert

回答

1

如果性能是不是一個主要問題 - 如果你只在12點評價,我懷疑這是不是 - 那麼你可以利用方便的sympy圖書館爲你做很多工作。例如:

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

我們可以在它返回的函數等包裝這件事:

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 

,我們可以再申請,甚至超越了輕鬆抵達正則表達式的更復雜的情況:

>>> 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 
+0

這正是我所需要的,非常感謝@DSM – daydreamer

+0

偉大的lib,但警告似乎明確警告與eval()相同的危險:http://docs.sympy.org/latest/tutorial/basic_operations .html#轉換字符串到sympy表達式 – vinyll

+0

@vinyll:是的。他們沿着路徑使用'eval',所以對於不可信的輸入是不安全的。但是非常方便。 – DSM

0

如果你想解析「功能」的字符串,你可以做這樣的事情:

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.4085456893295, 4230.676492114911, 4514.949840987468, 4738.019242139209] 

這種方法假定該函數的字符串永遠是形式的

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

並通過從字符串中提取浮點數並使用它們生成實際的Python函數來工作。

+1

這仍然需要從數據庫「手動粘貼」? –

+0

@hayden不 - 請參閱我的編輯。 – arshajii

0

您可以將功能作爲數據庫蟒蛇expersion,當你得到字符串只是做類似的eval(funcstr.replace(「X」,「y值」))。

要告訴你一個例子:

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

此時VAL進行評估,以15

+0

您可以使用這種方法來將此字符串調整爲Python嗎? –

0

由於NPE說,這裏的正確答案是寫一個解析器(和簡單的解釋器)爲您表達語言。

,或者甚至更好,如果可能的話,產生在Python表達式擺在首位,而不是在這幾乎是但不完全兼容與Python的一個子集的語言。如果語言只是一種表示多項式係數列表的方法,那麼將其表示爲系列列表,這將比任何實際的通用語言更容易解析。例如,假設在數據庫中保存這樣的:

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

然後,執行在Python中,你可以這樣做:

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)) 

然後:

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

但是,如果你真的,真的想在不更改數據庫中的內容的情況下執行此操作,只需將其轉換爲Python表達式並對其進行評估即可:

>>> 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] 

但是,你可能不想這樣做。

而且,如果你這樣做,你可能想要寫上你的實際語言的作品,而不是一個刺在這黑暗的基礎上只舉一個例子你的語言的猜測......

0

如果變壓器你信任你的源代碼,你可以用正則表達式和eval做這樣的:

# deletes the simicolon and everything before the space 
my_str = start_str.split('=')[1][:-1] 
# change^to ** because that's 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)]