2010-12-07 16 views
2

最小二乗法のフィッティングルーチンに渡す任意の数のピークに対して関数を作成する必要があります。 f(p, x) = p[0]*50 + p[1]*60*xPythonの動的関数構築

:50、60返す関数の値を持つf(p, x) = p[0]*50

二つの用語:各ピークの50返す関数の値を持つ

1期すなわち関数内の余分な用語は、そこにあります50での値との3項、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

+0

ええ、あなたが望むものを推測するのはちょっと難しいです。特に最初のものが 'fn' alotを上書きするだけなので... –

+0

ああ、2回目の試行で、デバッグしようとしたときにコードをコピーしたと思われます。リストを返さないでください。リストの合計を戻す必要があります...また、目的の結果を少し良く説明しました。 – Brendan

答えて

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

ああ、これははるかに簡単です!なぜ私はこれを考えなかったのか分かりません... – Brendan

0

簡単な修正は

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

Ah 、これは '範囲外のリストインデックス'エラーを出すようですか? – Brendan

+0

@Brendan、ええ、私はあまりにも閉鎖する必要があります。 –

1

クロージャは、その作成の時に外側のスコープ内の変数の値をキャプチャしていない、彼らは実際にこれらの変数をキャプチャし、デフォルトのパラメータで各fnへの参照を格納します。 [lambda: i for i in range(5)]は、すべてが同じものを参照するので、4つを返す5つの関数を提供します。i(繰り返しが終了すると4つです)。これを回避するには、デフォルトの引数(関数定義時のバインド値)を使用します。[lambda i=i: i for i in range(5)]は期待通りに機能します。

また、enumerateを使用してください。これ、一緒にfnラムダ作ると、同じように読めるIMO、にちょうど2つのをあなたのコードを減らすことができ、ライン(私は2番目のバージョンを仮定しているコメントで示されているように、最初は、より多くの方法で壊れているようだ):

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) 
+0

これらの用語のそれぞれは適切な価値を与えます(ただし、後に続く言葉の和です - 私の悪い、質問のコメントを参照してください) - これをforループに入れて質問のようにまとめてもいいですこれを行うより簡潔な方法がありますか? – Brendan

+0

@Brendan:確かに、 'sum'が組み込まれています。 – delnan

+0

ああ、平凡なPythonで(私は通常Numpyを使用しています)このようなことが分かっていませんでした。もし私がこれを2番目の答えとして指名することができたら、 – Brendan

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は、彼らが 構文を説明するために使用されていることを意味する、 構文変数です。実装の問題では、ドメイン内の何かを意味する良い名前を実際に使用する必要があります。そのため、多くの場合、問題を理解しやすくなります。

+0

うん、関数ではなくジェネレータを返します。フィッティングルーチンが働く(数学的な意味での)関数になるために – Brendan

+0

@ブレンダンええ、前回の2回目の試みと同じように書いています。あなたが見ることができるように、それは和にそれを変換するために多くを取る。 –

+0

ええ、私の悪い。これもうまくいきます - ありがとう! – Brendan

関連する問題