我必须在python 3.4中编写一个需要以下内容的任务: - 程序要求用户输入由多个子模型以字符串形式制作的数据模型,如下所示:
# the program ask :
please input the submodel1
# user will input:
A = a*x + b*y*exp(3*c/d*x)
# then the program ask :
-> please input the submodel2
# user will input:
B = e*x + f*y*exp(3*h/d*x)
# then the program ask :
-> please input the main model:
# user will input:
Y = A*x - exp(B**2/y)
然后程序采用这些模型(字符串)并对它们执行一些操作,例如将主模型曲线拟合到现有数据并绘制结果并显示参数值。 这里的想法是让用户在运行时自由选择模型,而无需将其编程为应用程序内的功能。 我的问题在于将字符串转换或解释为返回值的python函数。我探索了类似eval()函数的解决方案,但我正在寻找一个类似于MatLab的解决方案
func = sym('string')
func = matlabfunction(func)
创建一个匿名函数,您可以轻松处理它 希望我明确表示,如果需要进一步澄清,请告诉我, 解决方案应该与python 3.4兼容 提前致谢
答案 0 :(得分:0)
您可以使用以下解析:
https://pypi.python.org/pypi/parse
并训练你的解析器识别数学表达式,
看这个例子(python27):
http://www.nerdparadise.com/tech/python/parsemath/
# A really simple expression evaluator supporting the
# four basic math functions, parentheses, and variables.
class Parser:
def __init__(self, string, vars={}):
self.string = string
self.index = 0
self.vars = {
'pi' : 3.141592653589793,
'e' : 2.718281828459045
}
for var in vars.keys():
if self.vars.get(var) != None:
raise Exception("Cannot redefine the value of " + var)
self.vars[var] = vars[var]
def getValue(self):
value = self.parseExpression()
self.skipWhitespace()
if self.hasNext():
raise Exception(
"Unexpected character found: '" +
self.peek() +
"' at index " +
str(self.index))
return value
def peek(self):
return self.string[self.index:self.index + 1]
def hasNext(self):
return self.index < len(self.string)
def skipWhitespace(self):
while self.hasNext():
if self.peek() in ' \t\n\r':
self.index += 1
else:
return
def parseExpression(self):
return self.parseAddition()
def parseAddition(self):
values = [self.parseMultiplication()]
while True:
self.skipWhitespace()
char = self.peek()
if char == '+':
self.index += 1
values.append(self.parseMultiplication())
elif char == '-':
self.index += 1
values.append(-1 * self.parseMultiplication())
else:
break
return sum(values)
def parseMultiplication(self):
values = [self.parseParenthesis()]
while True:
self.skipWhitespace()
char = self.peek()
if char == '*':
self.index += 1
values.append(self.parseParenthesis())
elif char == '/':
div_index = self.index
self.index += 1
denominator = self.parseParenthesis()
if denominator == 0:
raise Exception(
"Division by 0 kills baby whales (occured at index " +
str(div_index) +
")")
values.append(1.0 / denominator)
else:
break
value = 1.0
for factor in values:
value *= factor
return value
def parseParenthesis(self):
self.skipWhitespace()
char = self.peek()
if char == '(':
self.index += 1
value = self.parseExpression()
self.skipWhitespace()
if self.peek() != ')':
raise Exception(
"No closing parenthesis found at character "
+ str(self.index))
self.index += 1
return value
else:
return self.parseNegative()
def parseNegative(self):
self.skipWhitespace()
char = self.peek()
if char == '-':
self.index += 1
return -1 * self.parseParenthesis()
else:
return self.parseValue()
def parseValue(self):
self.skipWhitespace()
char = self.peek()
if char in '0123456789.':
return self.parseNumber()
else:
return self.parseVariable()
def parseVariable(self):
self.skipWhitespace()
var = ''
while self.hasNext():
char = self.peek()
if char.lower() in '_abcdefghijklmnopqrstuvwxyz0123456789':
var += char
self.index += 1
else:
break
value = self.vars.get(var, None)
if value == None:
raise Exception(
"Unrecognized variable: '" +
var +
"'")
return float(value)
def parseNumber(self):
self.skipWhitespace()
strValue = ''
decimal_found = False
char = ''
while self.hasNext():
char = self.peek()
if char == '.':
if decimal_found:
raise Exception(
"Found an extra period in a number at character " +
str(self.index) +
". Are you European?")
decimal_found = True
strValue += '.'
elif char in '0123456789':
strValue += char
else:
break
self.index += 1
if len(strValue) == 0:
if char == '':
raise Exception("Unexpected end found")
else:
raise Exception(
"I was expecting to find a number at character " +
str(self.index) +
" but instead I found a '" +
char +
"'. What's up with that?")
return float(strValue)
def evaluate(expression, vars={}):
try:
p = Parser(expression, vars)
value = p.getValue()
except Exception as (ex):
msg = ex.message
raise Exception(msg)
# Return an integer type if the answer is an integer
if int(value) == value:
return int(value)
# If Python made some silly precision error
# like x.99999999999996, just return x + 1 as an integer
epsilon = 0.0000000001
if int(value + epsilon) != int(value):
return int(value + epsilon)
elif int(value - epsilon) != int(value):
return int(value)
return value
print evaluate("1 + 2 * 3")
print evaluate("(1 + 2) * 3")
print evaluate("-(1 + 2) * 3")
print evaluate("(1-2)/3.0 + 0.0000")
print evaluate("1 + pi / 4")
print evaluate("(a + b) / c", { 'a':1, 'b':2, 'c':3 })
print evaluate("(x + e * 10) / 10", { 'x' : 3 })
print evaluate("1.0 / 3 * 6")
print evaluate("(1 - 1 + -1) * pi")
print evaluate("pi * e")
答案 1 :(得分:0)
我通过创建一个小解析器找到了我的问题的解决方案,或者让我们说一个基于python库PLY的非常小的dsl,请参考这个网页了解详细信息: http://www.dabeaz.com/ply/ply.html#ply_nn1 和这个项目: https://github.com/maldoinc/mamba
答案 2 :(得分:0)
lmfit(http://lmfit.github.io/lmfit-py/)有一个您可能会觉得有用的ExpressionModel:
/_sql
这使用asteval(http://newville.github.io/asteval),因此支持相当丰富的Python语法子集和numpy常量和ufunc,包括import numpy as np
import matplotlib.pyplot as plt
from lmfit.models import ExpressionModel
# make fake data
x = np.linspace(-10, 10, 201)
amp, cen, wid = 3.4, 1.8, 0.5
y = amp * np.exp(-(x-cen)**2 / (2*wid**2)) / (np.sqrt(2*np.pi)*wid)
y += np.random.normal(size=len(x), scale=0.01)
# create model from expression
model= ExpressionModel("amp * exp(-(x-cen)**2 /(2*wid**2))/(sqrt(2*pi)*wid)")
# fit data to that model
result = model.fit(y, x=x, amp=5, cen=5, wid=1)
# show results
print(result.fit_report())
plt.plot(x, y, 'bo')
plt.plot(x, result.init_fit, 'k--')
plt.plot(x, result.best_fit, 'r-')
plt.show()
,sqrt
,exp
,{{ 1}},等等。