2010-12-07 34 views
2

我需要为任意数量的峰值创建一个函数,以传递给最小二乘拟合例程。对于每一个峰存在于50次返回的函数的函数的额外项,即Python中的动态函数构建

一个术语具有值:f(p, x) = p[0]*50 + p[1]*60*x

:在50,60返回的函数f(p, x) = p[0]*50

两个方面与值三个方面与值在50,60,70返回:f(p, x) = p[0]*50 + p[1]*60*x + p[2]*70*x^2

几个幼稚尝试如下所示,

def foo(vals): 
    fn = lambda p, x: 0 
    i = 0 
    for v in vals: 
     fn = lambda p, x : fn(p, x) + p[i] * v * x**i 
     i += 1 
    return fn 
# Causes a recursion error (I think)

第二次尝试......

def bar(vals): 
    terms = [] 
    i = 0 
    for v in vals: 
     terms.append(lambda x, p: p[i] * v * x**i) 
     i += 1 
    def fn(x, p): 
     tvals = [t(x, p) for t in terms] 
     sum = 0 
     for t in terms: 
      sum = sum + t(x, p) 
     return sum 
    return fn 
# Generates the wrong values 

我怀疑这是引用一个问题,即Python将参照表声明等,但是这是一个有点复杂解开 - 任何帮助,将不胜感激!

+0

你能提供一个测试用例,显示你期待得到什么(和你在第二种情况中得到什么)? – NPE 2010-12-07 13:17:03

+0

是的,有点难以猜到你想要什么,特别是因为第一次只是覆盖`fn`多... – 2010-12-07 13:22:21

+0

嗯,它似乎在我试图调试时复制代码的第二次尝试时,它不应该返回一个列表,它应该返回该列表的总和......并且我更好地解释了期望的结果 – Brendan 2010-12-07 14:18:22

回答

2

如何:

def foo(vals): 
    def f(p,x): 
     result=0 
     for i,(av,ap) in enumerate(zip(vals,p)): 
      result+=av*ap*(x**i) 
     return result 
    return f 

print(foo([50])([2],3)) 
# f(p,x)=50*2 
# 100 
print(foo([50,60])([2,3],4)) 
# f(p,x)=50*2+60*3*x 
# 820 
0

一个简单的修改存储在默认参数,每个fn参考

def foo(vals): 
    fn = lambda p, x: 0 
    i = 0 
    for v in vals: 
     fn = lambda p, x, f=fn, i=i: f(p, x) + p[i] * v * x**i 
     i += 1 
    return fn 
+0

啊,这似乎给了'列表索引超出范围'的错误? – Brendan 2010-12-07 14:45:48

+0

@Brendan,是啊,需要在`i`上关闭。 – 2010-12-07 20:54:45

1

瓶盖不要在他们的创作时间捕捉在外部范围变量的值,他们真正抓住这些变量。 [lambda: i for i in range(5)]给你五个函数,全部返回4,因为它们都指向相同的i(迭代结束时为4)。您可以使用默认参数(在函数定义时绑定值)来解决此问题:[lambda i=i: i for i in range(5)]按预期工作。

另外,使用enumerate。这一点,加上制作fn拉姆达可以降低代码到只有两个,伊莫同样可读,线(我假设的第二个版本,第一个打破似乎在很多方面,如在评论中所示):

def bar(vals): 
    terms = [lambda x, p, i=i, v=v: p[i] * v * x**i for i, v in enumerate(vals)] 
    return lambda x, p: sum(term(x, p) for term in terms) 
1

你可以写整个事情作为一个返回闭包功能:

def make_function(vals): 
    def evaluate(x,p): 
     return sum(p[i] * v * x**i 
        for i,v in enumerate(vals)) 
    return evaluate 

你正在运行与terms功能的问题经常出现。我之前写了一个长的解释about this problem,希望它会有帮助。

顺便说一句,foobar句法变量,这意味着它们被用于解释语法。对于实现问题,您应该真正使用在域中有用的好名称,这通常会使问题更容易理解。