使用 DEAP 的人类可读输出
Human-readable output with DEAP
我正在使用 DEAP 对 table 数据进行符号回归,即找到最适合数据的函数。不幸的是,我找不到以人类可读格式获取结果的方法。例如,如果我这样做
best_ind = tools.selBest(pop, 1)[0]
print("Best individual is %s" % (best_ind))
我的输出可能类似于
Best individual is add(mul(add(x, 2), div(y, add(x, y))), 1)
但这对人类来说很难解释。有没有办法以更像
的方式打印结果
(x+2)*(y/(x+y))+1
您可以先使用 sympy.simplify
import sympy
expr = "Add(x, 2)"
sympy.simplify(expr) # x + 2
但是,sympy 希望 add、mul 等大写。您还需要将 Div(a, b)
翻译成 Mul(a, 1/b)
。
您可以像这样更改 primitive.format
方法来做到这一点:
def convert_inverse_prim(prim, args):
"""
Convert inverse prims according to:
[Dd]iv(a,b) -> Mul[a, 1/b]
[Ss]ub(a,b) -> Add[a, -b]
We achieve this by overwriting the corresponding format method of the sub and div prim.
"""
prim = copy.copy(prim)
prim.name = re.sub(r'([A-Z])', lambda pat: pat.group(1).lower(), prim.name) # lower all capital letters
converter = {
'sub': lambda *args_: "Add({}, Mul(-1,{}))".format(*args_),
'div': lambda *args_: "Mul({}, Pow({}, -1))".format(*args_)
}
prim_formatter = converter.get(prim.name, prim.format)
return prim_formatter(*args)
此代码取自glyph。
Ohjeahs 的回答与提供的不一样。我修改了提供的代码并在下面提供。
import sympy
def convert_inverse_prim(prim, args):
"""
Convert inverse prims according to:
[Dd]iv(a,b) -> Mul[a, 1/b]
[Ss]ub(a,b) -> Add[a, -b]
We achieve this by overwriting the corresponding format method of the sub and div prim.
"""
prim = copy.copy(prim)
#prim.name = re.sub(r'([A-Z])', lambda pat: pat.group(1).lower(), prim.name) # lower all capital letters
converter = {
'sub': lambda *args_: "Add({}, Mul(-1,{}))".format(*args_),
'protectedDiv': lambda *args_: "Mul({}, Pow({}, -1))".format(*args_),
'mul': lambda *args_: "Mul({},{})".format(*args_),
'add': lambda *args_: "Add({},{})".format(*args_)
}
prim_formatter = converter.get(prim.name, prim.format)
return prim_formatter(*args)
def stringify_for_sympy(f):
"""Return the expression in a human readable string.
"""
string = ""
stack = []
for node in f:
stack.append((node, []))
while len(stack[-1][1]) == stack[-1][0].arity:
prim, args = stack.pop()
string = convert_inverse_prim(prim, args)
if len(stack) == 0:
break # If stack is empty, all nodes should have been seen
stack[-1][1].append(string)
return string
sympy.simplify(stringify_for_sympy(best_ind))
这个小的很适合我:
from sympy import sympify
locals = {
'sub': lambda x, y : x - y,
'div': lambda x, y : x/y,
'mul': lambda x, y : x*y,
'add': lambda x, y : x + y,
'neg': lambda x : -x,
'pow': lambda x, y : x**y,
}
# ind = 'div(add(div(x, mul(y, y)), 1), mul(x, y))'
print(f'original: {ind}')
expr = sympify(str(ind) , locals=locals)
print(f'simplified: {expr}')
输出:
original: div(add(div(x, mul(y, y)), 1), mul(x, y))
simplified: (x/y**2 + 1)/(x*y)
它甚至显示了在 Jupyter 笔记本中显示的 LaTex:
display(expr)
我正在使用 DEAP 对 table 数据进行符号回归,即找到最适合数据的函数。不幸的是,我找不到以人类可读格式获取结果的方法。例如,如果我这样做
best_ind = tools.selBest(pop, 1)[0]
print("Best individual is %s" % (best_ind))
我的输出可能类似于
Best individual is add(mul(add(x, 2), div(y, add(x, y))), 1)
但这对人类来说很难解释。有没有办法以更像
的方式打印结果(x+2)*(y/(x+y))+1
您可以先使用 sympy.simplify
import sympy
expr = "Add(x, 2)"
sympy.simplify(expr) # x + 2
但是,sympy 希望 add、mul 等大写。您还需要将 Div(a, b)
翻译成 Mul(a, 1/b)
。
您可以像这样更改 primitive.format
方法来做到这一点:
def convert_inverse_prim(prim, args):
"""
Convert inverse prims according to:
[Dd]iv(a,b) -> Mul[a, 1/b]
[Ss]ub(a,b) -> Add[a, -b]
We achieve this by overwriting the corresponding format method of the sub and div prim.
"""
prim = copy.copy(prim)
prim.name = re.sub(r'([A-Z])', lambda pat: pat.group(1).lower(), prim.name) # lower all capital letters
converter = {
'sub': lambda *args_: "Add({}, Mul(-1,{}))".format(*args_),
'div': lambda *args_: "Mul({}, Pow({}, -1))".format(*args_)
}
prim_formatter = converter.get(prim.name, prim.format)
return prim_formatter(*args)
此代码取自glyph。
Ohjeahs 的回答与提供的不一样。我修改了提供的代码并在下面提供。
import sympy
def convert_inverse_prim(prim, args):
"""
Convert inverse prims according to:
[Dd]iv(a,b) -> Mul[a, 1/b]
[Ss]ub(a,b) -> Add[a, -b]
We achieve this by overwriting the corresponding format method of the sub and div prim.
"""
prim = copy.copy(prim)
#prim.name = re.sub(r'([A-Z])', lambda pat: pat.group(1).lower(), prim.name) # lower all capital letters
converter = {
'sub': lambda *args_: "Add({}, Mul(-1,{}))".format(*args_),
'protectedDiv': lambda *args_: "Mul({}, Pow({}, -1))".format(*args_),
'mul': lambda *args_: "Mul({},{})".format(*args_),
'add': lambda *args_: "Add({},{})".format(*args_)
}
prim_formatter = converter.get(prim.name, prim.format)
return prim_formatter(*args)
def stringify_for_sympy(f):
"""Return the expression in a human readable string.
"""
string = ""
stack = []
for node in f:
stack.append((node, []))
while len(stack[-1][1]) == stack[-1][0].arity:
prim, args = stack.pop()
string = convert_inverse_prim(prim, args)
if len(stack) == 0:
break # If stack is empty, all nodes should have been seen
stack[-1][1].append(string)
return string
sympy.simplify(stringify_for_sympy(best_ind))
这个小的很适合我:
from sympy import sympify
locals = {
'sub': lambda x, y : x - y,
'div': lambda x, y : x/y,
'mul': lambda x, y : x*y,
'add': lambda x, y : x + y,
'neg': lambda x : -x,
'pow': lambda x, y : x**y,
}
# ind = 'div(add(div(x, mul(y, y)), 1), mul(x, y))'
print(f'original: {ind}')
expr = sympify(str(ind) , locals=locals)
print(f'simplified: {expr}')
输出:
original: div(add(div(x, mul(y, y)), 1), mul(x, y))
simplified: (x/y**2 + 1)/(x*y)
它甚至显示了在 Jupyter 笔记本中显示的 LaTex:
display(expr)