0

パラメータの辞書をミニマイザーに渡すことで、 PyMinuit関数の最小化を実行することは可能ですか?

たとえば、PyMinuit の通常の使用は、次のようなものを使用して呼び出されます。

def f(x, a, b): return a + b*x

def chi2(a,b):
    c2 = 0.
    for x, y, yerr in data:
        c2 += (f(x, a, b) - y)**2 / yerr**2
    return c2

m = minuit.Minuit(chi2)
m.migrad()

この質問から、PyMinuit がイントロスペクションを使用してパラメーター x と y を決定することを理解しています (ただし、それが何を意味するのか完全にはわかりません)。理想的には、次のようなことができるようになりたいです。

p = dict()
p['x'] = 0.
p['y'] = 0.

def f(x,a,b): return a + b*x

def chi2():
    c2 = 0.
    for x, y, yerr in data:
        c2 += (f(x, a, b) - y)**2 / yerr**2
    return c2

m = minuit.Minuit(chi2,**p)
m.migrad()

あるいは:

p = <dictionary of parameters + initial values>

model = <list containing strings representing functions e.g. 'a*b+a**2*x'>

data = x, y, yerr, model

def chi2():
    c2 = 0.
    for x, y, yerr, model in data:
        c2 += (eval(model,{"__builtins__":None},p) - y)**2 / yerr**2
    return c2

m = minuit.Minuit(chi2)
m.migrad()    

Googleグループの問題ページで、整数入力から「偽のコード」と「偽の関数」を生成した同様の問題の回避策を見ました(リンクに従ってください)。辞書 p で同様のことを試しました:

class fake_code:
    def __init__(self,p):
        self.co_argcount = len(p)
        self.co_varnames = tuple(p.keys())
        print tuple(p.keys())

class fake_function:
    def __init__(self,p):
        self.func_code = fake_code(p)
    def __call__(self,*args):
        c2 = 0.
        print args
        for x, y, yerr in data:
            c2 += (f(x, a, b) - y)**2 / yerr**2
    return c2

しかし、何らかの理由ですべてのパラメータが「修正済み」に分類されており、それらを「修正解除」できないようです。

このようにすることは可能だと思いますが、これが最善の方法であるかどうか、または試みるべきかどうかさえ、pythonについて十分に知りません。誰かがこれに光を当てることができれば、私は知って感謝しています. :)

4

3 に答える 3

1

この以下はほとんどテストされていません。私は通常これを避けようとしますが、これに役立つ可能性のあるコメントで言及した簡単な方法をよりよく説明するために例外を設けています。これは、ここに示されている最初の例に基づいています。

import minuit

def minuit_call(func, **kwargs):
    CALL_TEMPLATE = "minuit.Minuit({0.__name__}, {1})"
    arg_str = ', '.join('{}={}'.format(k, v) for k,v in kwargs.iteritems())
    return eval(CALL_TEMPLATE.format(func, arg_str))

def f(x, y):
    return ((x-2) / 3)**2 + y**2 + y**4

m = minuit_call(f, x=0, y=0)
m.migrad()

ご覧のとおり、使用されるテンプレートは非常に簡単であり、最小化するために関数の本体にあるコードを手動でフォーマット文字列に変換する必要はありませんでした。

于 2013-02-18T19:55:54.443 に答える
1

回答が遅くなる場合があります。これを試してみてください。とりわけこの特定の機能が不足しているため、私はそれを書きました。

http://iminuit.github.com/iminuit/

ここで一般的なコスト関数を記述する方法の例を参照してください。

http://nbviewer.ipython.org/urls/raw.github.com/iminuit/iminuit/master/tutorial/hard-core-tutorial.ipynb

ただし、カイ ^ 2/尤度関数を書くのは簡単ですが、確率で既に書かれています。

http://iminuit.github.com/probfit/

于 2013-03-28T10:08:45.757 に答える
1

OK、自分の質問に答えるのは好きではありませんが、 を使用して解決策を見つけたと思いますexec。テンプレートで関数を定義し、chi2関数を使用して実行時にビルドする場合make_chi_squared、それは可能です。私が思いついた解決策を以下に示します。

import minuit
import numpy

chi_squared_template = """
def chi_squared(%(params)s):
    li = [%(params)s]
    for i,para in enumerate(li):
        p[l[i]] = para
    return (((f(data_x, p) - data_y) / errors) ** 2).sum()
"""

l = ['a1','a2','a3','a4']

p = dict()
p['a1'] = 1.
p['a2'] = 1.
p['a3'] = 1.
p['a4'] = 1.

def make_chi_squared(f, data_x, data_y, errors):
    params = ", ".join(l)
    exec chi_squared_template % {"params": params}
    return chi_squared

def f(x,p):
    return eval('a1 + a2*x + a3*x**2 + a4*x**3',
                {"__builtins__":locals()},
                p)

data_x = numpy.arange(50)
errors = numpy.random.randn(50) * 0.3
data_y = data_x**3 + errors

chi_squared = make_chi_squared(f, data_x, data_y, errors)

m = minuit.Minuit(chi_squared)
m.printMode = 1
m.migrad()
print m.values
p = m.values
print p

少し面倒ですし、この種の問題を処理する最善の方法かどうかはわかりませんが、うまくいきます!

于 2013-02-18T10:30:21.403 に答える