Я пытаюсь написать процедуру, которая нормализует (переписывает) математическое уравнение, которое может иметь более одного символа в LHS, чтобы оно имело только один.

Следующий код иллюстрирует то, что я хочу сделать

Предположим, у меня есть уравнение

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

Я хочу решить для х или вернуть

x=x1*exp(-a+by)

Используя 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)]

Я пытаюсь автоматизировать это для диапазона строк ввода следующим образом

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)

Генерирует результат

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

Любая помощь для этого py новичка, будет принята с благодарностью.

0
A Burns 3 Июл 2019 в 00:56

4 ответа

Лучший ответ

Мой коллега (Иб Хансен) дал мне очень хорошее и элегантное решение исходной проблемы (как решить сложное выражение), которое обошло решение по манипуляции со строками, с которым боролся мой первоначальный вопрос и на которое было дано большинство ответов.

Его решение - использовать sympify и solve от 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}'

Это работает отлично

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)

С результатом

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)
0
A Burns 29 Авг 2019 в 19:13

var('a b 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)]

Поэтому на самом деле нет необходимости использовать eval или иметь переменную, соответствующую имени символа: S может преобразовать строку в выражение, а free_symbols может определить, какие символы присутствуют. Помещение их в словарь с ключами, являющимися именами символов, позволяет извлекать их из словаря со строкой.

2
smichr 3 Июл 2019 в 04:32

Я думаю, что вы хотите сгенерировать строку из этих двух операторов, а затем вы можете оценить эту строку

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

Первая строка говорит - дайте мне строку, но запустите код Python между {}, прежде чем вернуть его. Например

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

>> Adding two numbers: (2+3) = 5
0
MichaelD 2 Июл 2019 в 22:11

Во-первых, может быть, это поможет сделать ваш код немного плотнее.

Если я правильно понимаю, вы пытаетесь назначить переменную, используя список имен. Вы можете использовать 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
0
Nakor 2 Июл 2019 в 22:25