简体   繁体   English

如何动态生成python符号语句?

[英]How can I dynamically generate a python symbol statement?

I am trying to write a routine that normalizes (rewrites) a mathematical equation that may have more than one symbol on the LHS so that it only has one. 我正在尝试编写一个例程,该例程对LHS上可能有多个符号的数学方程进行规范化(重写),因此它只有一个符号。

The following code illustrates what I want to do 以下代码说明了我想做什么

Assume I have an equation 假设我有一个方程

ln(x)-ln(x1)= -(a+by)

I want to solve for x or return 我想求解x或返回

x=x1*exp(-a+by)

Using sympy I can do the following 使用sympy我可以执行以下操作

from sympy import *

formula=' log(x)-log(x1) =-(a+b*y)'
lhs,rhs=formula.split('=',1)
x,x_1,y,a,b,y=symbols('x x_1 y a b y')    
r=sympy.solve(eval(lhs)-eval(rhs),x)
r

==> 
Output: [x1*exp(-a - b*y)]

I am trying to automate this for a range of input lines as follows 我正在尝试如下自动进行一系列输入

from sympy import *
import re

# eventually to be read ina loop from a file
formula="DLOG(SAUMMCREDBISCN/SAUNECONPRVTXN) =-0.142368233181-0.22796245228*(LOG(SAUMMCREDBISCN(-1)/SAUNECONPRVTXN(-1))+0.2*((SAUMMLOANINTRCN(-1)-SAUINTR(-1))/100)-LOG(SAUNYGDPMKTPKN(-1)))+0.576050997065*SAUNYGDPGAP_/100"

#try to convert formula into a string containing just the synbols
sym1=formula.replace("*"," ")
sym1=sym1.replace("DLOG"," ")
sym1=sym1.replace("LOG"," ")
sym1=sym1.replace("EXP"," ")
sym1=sym1.replace("RECODE"," ")


sym1=re.sub('[()/+-\=]',' ',sym1)
sym1=re.sub(' +',' ',sym1)
#This logic works for this particular formula
sym1

#now generate a string that has, instead of spaces between symbols
ss2=sym1.replace(' ',',')

#This is the part that does not work I want to generate a command that effectively says
#symbol,symbol2,..,symboln=symbols('symbol1 symbol2 ... symboln')

#tried this but it fails
eval(ss2)=symbols(sym1)

Generates the result 产生结果

    eval(ss2)=symbols(sym1)
                           ^
SyntaxError: can't assign to function call

Any help for this py noob, would be greatly appreciated. 对于这个py新手的任何帮助,将不胜感激。

var('ab c') will inject symbol name 'a', 'b', 'c' into the namespace but perhaps @Blorgbeard is asking about lists or dicts because instead of creating many symbols you could put the symbols in a dictionary and then access them by name: var('ab c')会将符号名称'a','b','c'注入到名称空间中,但是@Blorgbeard可能会询问列表或字典,因为与其创建许多符号,您还可以将这些符号放入字典中,然后然后按名称访问它们:

>>> formula=' log(x)-log(x1) =-(a+b*y)'
>>> eq = Eq(*map(S, formula.split('=', 1)))
>>> v = dict([(i.name, i) for i in eq.free_symbols]); v
{'y': y, 'b': b, 'x': x, 'x1': x1, 'a': a}
>>> solve(eq, v['x'])
[x1*exp(-a - b*y)]

So it is not actually necessary to use eval or to have a variable matching a symbol name: S can convert a string to an expression and free_symbols can identify which symbols are present. 因此,实际上没有必要使用eval或具有与符号名称匹配的变量: S可以将字符串转换为表达式,而free_symbols可以识别存在哪些符号。 Putting them in a dictionary with keys being the Symbol name allows them to be retrieved from the dictionary with a string. 将它们放在字典中,键为符号名称,可以使用字符串从字典中检索它们。

I think what you want to generate a string from these two statements and then you can eval that string 我认为您想从这两个语句生成一个字符串,然后可以评估该字符串

str_eq = f'{ss2} = {symbols(sym1)}'
print(str_eq)
>>' ,SAUMMCREDBISCN,SAUNECONPRVTXN,SAUMMCREDBISCN,SAUNECONPRVTXN,SAUMMLOANINTRCN,SAUINTR,SAUNYGDPMKTPKN,SAUNYGDPGAP_, = (SAUMMCREDBISCN, SAUNECONPRVTXN, SAUMMCREDBISCN, SAUNECONPRVTXN, SAUMMLOANINTRCN, SAUINTR, SAUNYGDPMKTPKN, SAUNYGDPGAP_)'

The first line says - give me a string but run the python code between the {} before returning it. 第一行说-给我一个字符串,但是在返回之前在{}之间运行python代码。 For instance 例如

print(f'Adding two numbers: (2+3) = {2 + 3}')

>> Adding two numbers: (2+3) = 5

First, maybe this could help make your code a bit denser. 首先,也许这可以使您的代码更加密集。

If I understand correctly, you're trying to assign a variable using a list of names. 如果我理解正确,您正在尝试使用名称列表来分配变量。 You could use vars()[x]= : 您可以使用vars()[x]=

import re
from sympy import symbols

symbol_names = re.findall("SAU[A-Z_]+",formula)
symbol_objs = symbols(symbol_names)

for sym_name,sym_obj in zip(symbol_names,symbol_objs):
    vars()[sym] = sym_obj

A colleague of mine (Ib Hansen) gave me a very nice and elegant solution to the original problem (how to solve for the complicated expression) that by-passed the string manipulation solution that my original question was struggling with and which most answers addressed. 我的一位同事(Ib Hansen)为我提供了一个很好而优雅的解决方案,解决了最初的问题(如何解决复杂的表达式),该解决方案绕过了我原来的难题所困扰的字符串处理解决方案,并且大多数答案都得到了解决。

His solution is to use sympify and solve from sympy 他的解决方案是使用症状和从sympy 解决

from sympy import sympify, solve
import re

def normalize(var,eq,simplify=False,manual=False):  
    '''normalize an equation with respect to var using sympy'''
    lhs, rhs = eq.split('=')
    kat = sympify(f'Eq({lhs},{rhs})')
    var_sym = sympify(var)
    out = str(solve(kat, var_sym,simplify=simplify,manual=manual))[1:-1] 
    return f'{var} = {out}'

This works perfectly 这完美地工作

from sympy import sympify, solve
import re

def norm(var,eq,simplify=False,manual=False):  
    '''normalize an equation with respect to var using sympy'''
    lhs, rhs = eq.split('=')
    kat = sympify(f'Eq({lhs},{rhs})')
    var_sym = sympify(var)
    out = str(solve(kat, var_sym,simplify=simplify,manual=manual))[1:-1] # simplify takes for ever
    return f'{var} = {out}'

``` Re write equation spelling out the dlog (delta log) function that python does no know, and putting log into lowe case '''

test8=norm('saummcredbiscn','log(saummcredbiscn/sauneconprvtxn) -log(saummcredbiscn(-1)/sauneconprvtxn(-1)) =-0.142368233181-0.22796245228*(log(saummcredbiscn(-1)/sauneconprvtxn(-1))+0.2*((saummloanintrcn(-1)-sauintr(-1))/100)-log(saunygdpmktpkn(-1)))+0.576050997065*saunygdpgap_/100')
print (test8)

with result 结果

saummcredbiscn = 0.867301828366361*sauneconprvtxn*(saummcredbiscn(-1.0)/sauneconprvtxn(-1.0))**(19300938693/25000000000)*saunygdpmktpkn(-1.0)**(5699061307/25000000000)*exp(0.00576050997065*saunygdpgap_ + 0.00045592490456*sauintr(-1.0) - 0.00045592490456*saummloanintrcn(-1.0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM