我目前正在使用Python,我遇到了一个问题,我不知道在哪里抓吸管。请原谅我,如果某些初始的算法CS课程中涉及到这一点,我的背景真的是经济学。我正在处理财务数据,我知道输出和输入,我只是不知道如何达到操作顺序。
例如,我的最终市盈率为2,但输入为10(价格)和5(收益)。看看这个,我知道10/5相当于2.然而,问题是操作的顺序......这可能是加法,乘法,除法和平方根。
如果我只是
,这部分似乎可行inputs = [10,5]
output = 2
def deduction_int(inputs, output):
initial_output = 0
while initial_output != output:
try adding, try subtracting (inverse), try dividing(inverse)
打印'yay',当它自己弄清楚或有答案时
上面的代码看起来很明显,但是,当你向它添加3个变量时......
输入:10,5,7 输出:2.14
和(10 + 5)/ 7 = 2.14等情况。
我遇到了数字可能以不同顺序运行的情况。例如10 + 5在除以7之前运行。这是一种常见的算法类型的问题吗?如果是这样,我究竟在哪里寻找一些教科书描述(算法名称,教科书)?
谢谢!
答案 0 :(得分:2)
这是一种强力算法。
from __future__ import division
import itertools as IT
import operator
opmap = {operator.add: '+',
operator.mul: '*',
operator.truediv: '/'}
operators = opmap.keys()
def deduction_int(inputs, output):
iternums = IT.permutations(inputs, len(inputs))
iterops = IT.product(operators, repeat=len(inputs)-1)
for nums, ops in IT.product(iternums, iterops):
for result, rstr in combine(nums, ops):
if near(result, output, atol=1e-3):
return rstr
def combine(nums, ops, astr=''):
a = nums[0]
astr = astr if astr else str(a)
try:
op = ops[0]
except IndexError:
return [(a, astr)]
# combine a op (...)
result = []
for partial_val, partial_str in combine(nums[1:], ops[1:]):
r = op(a, partial_val)
if len(nums[1:]) > 1:
rstr = '{}{}({})'.format(astr, opmap[op], partial_str)
else:
rstr = '{}{}{}'.format(astr, opmap[op], partial_str)
assert near(eval(rstr), r)
result.append((r, rstr))
# combine (a op ...)
b = nums[1]
astr = '({}{}{})'.format(astr,opmap[op], b)
for partial_val, partial_str in combine((op(a, b),)+nums[2:], ops[1:],
astr):
assert near(eval(partial_str), partial_val)
result.append((partial_val, partial_str))
return result
def near(a, b, rtol=1e-5, atol=1e-8):
return abs(a - b) < (atol + rtol * abs(b))
def report(inputs, output):
rstr = deduction_int(inputs, output)
return '{} = {}'.format(rstr, output)
print(report([10,5,7], (10+5)/7))
print(report([1,2,3,4], 3/7.))
print(report([1,2,3,4,5], (1+(2/3)*(4-5))))
产量
(10+5)/7 = 2.14285714286
(1+2)/(3+4) = 0.428571428571
(1+5)/((2+4)*3) = 0.333333333333
主要思想是简单地枚举输入值的所有排序,以及运算符的所有排序。例如,
In [19]: list(IT.permutations([10,5,7], 3))
Out[19]: [(10, 5, 7), (10, 7, 5), (5, 10, 7), (5, 7, 10), (7, 10, 5), (7, 5, 10)]
然后将输入值的每个顺序与运算符的每个顺序配对:
In [38]: list(IT.product(iternums, iterops))
Out[38]:
[((10, 5, 7), (<built-in function add>, <built-in function mul>)),
((10, 5, 7), (<built-in function add>, <built-in function truediv>)),
((10, 5, 7), (<built-in function mul>, <built-in function add>)),
((10, 5, 7), (<built-in function mul>, <built-in function truediv>)),
...
combine
函数接受nums的排序和ops的排序,并枚举nums和ops的所有可能分组:
在[65]中:combine((10,5,7),(operator.add,operator.mul))
Out[65]: [(45, '10+(5*7)'), (45, '10+((5*7))'), (105, '(10+5)*7'), (105, '((10+5)*7)')]
它返回一个元组列表。每个元组都是一个2元组,由一个数值和字符串表示rstr
组成,分组操作的计算结果为该值。
所以,你只需循环遍历所有可能性并返回rstr
,在评估时,会产生一个接近output
的数字。
for nums, ops in IT.product(iternums, iterops):
for result, rstr in combine(nums, ops):
if near(result, output, atol=1e-3):
return rstr
一些有用的参考资料:
答案 1 :(得分:1)
因此,您将获得一些输入和输出,并且您希望找到生成它的表达式。
这样做的简单方法是通过蛮力,通过生成和测试各种表达方式。我的程序是通过从数字开始的简单表达式构建大表达式来实现的。一遍又一遍地增加了新生成的表达式与它们之前的所有内容的组合。
它打印出从简单到复杂的解决方案,直到内存不足为止。
#!python3
import operator
import decimal
import sys
# Automatically take care of divisions by zero etc
decimal.setcontext(decimal.ExtendedContext)
class Expression(object):
def __init__(self, left, right):
self.left = left
self.right = right
class Number(Expression):
def __init__(self, value):
self.value = decimal.Decimal(value)
def evaluate(self):
return self.value
def __str__(self):
return str(self.value)
class Addition(Expression):
def evaluate(self):
return self.left.evaluate() + self.right.evaluate()
def __str__(self):
return "({0} + {1})".format(self.left, self.right)
class Subtraction(Expression):
def evaluate(self):
return self.left.evaluate() - self.right.evaluate()
def __str__(self):
return "({0} - {1})".format(self.left, self.right)
class Multiplication(Expression):
def evaluate(self):
return self.left.evaluate() * self.right.evaluate()
def __str__(self):
return "({0} * {1})".format(self.left, self.right)
class Division(Expression):
def evaluate(self):
return self.left.evaluate() / self.right.evaluate()
def __str__(self):
return "({0} / {1})".format(self.left, self.right)
class Sqrt(Expression):
def __init__(self, subexp):
self.subexp = subexp
def evaluate(self):
return self.subexp.evaluate().sqrt()
def __str__(self):
return "sqrt({0})".format(self.subexp)
def bruteforce(inputs, output, wiggle):
inputs = [Number(i) for i in inputs]
output = decimal.Decimal(output)
wiggle = decimal.Decimal(wiggle)
expressions = inputs
generated = inputs
while True:
newgenerated = []
for g in generated:
for e in expressions:
newgenerated.extend([
Addition(g, e),
Subtraction(g, e),
Multiplication(g, e),
Division(g, e)
])
for e in expressions[0:len(expressions) - len(generated)]:
# Subtraction and division aren't commutative. This matters
# when the relation is not symmetric. However it is symmetric
# for the most recently generated elements, so we don't worry
# about commutivity for those.
newgenerated.extend([
Division(e, g),
Subtraction(e, g)
])
newgenerated.append(Sqrt(g))
for c in newgenerated:
if abs(c.evaluate() - output) < decimal.Decimal(.01):
print(c)
sys.stdout.flush()
expressions.extend(newgenerated)
generated = newgenerated
bruteforce((10, 5, 7), 2.14, .005)
打印
((10 + 5) / 7)
((10 - 7) * (5 / 7))
((10 - 7) / (7 / 5))
((10 / 7) + (5 / 7))
((5 + 10) / 7)
((5 / 7) * (10 - 7))
((5 / 7) + (10 / 7))
(sqrt(7) - (5 / 10))
这些都没有完全评估到2.14,但它们在0.005的“摆动”范围内是相同的。除了sqrt one 2.146之外,小数点后3位,它们都是2.143。
生成它们之后,它当然会遇到MemoryError崩溃。我甚至不想知道这个时间或空间的复杂性:)