是否可以通过将参数字典传递给最小化器来执行PyMinuit函数最小化?
例如,PyMineuit的常用用法可以称为使用以下内容:
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()
从这个问题中,我理解PyMineuit使用内省来确定参数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()
我在谷歌群组问题页面上看到了一个类似问题的解决方案,他们从整数输入中生成了"假代码"one_answers"假函数"(点击链接查看)。我用我的字典试了一些类似的东西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的了解还不够,无法判断这是否是最好的方法,甚至是否应该尝试。如果有人能对此有所了解,我将不胜感激
好吧,我不喜欢回答自己的问题,但我想我已经找到了使用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
这有点乱,我不确定这是否是处理这类问题的最佳方式,但它有效!
以下内容基本上未经测试,我通常会尽量避免这样做,但我破例向您更好地解释我在评论中提到的可能适用于此的简化方法。它基于这里显示的第一个示例。
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()
正如您所看到的,所使用的模板相当琐碎,创建它不需要手动将函数体中的任何代码翻译成格式化字符串。
回答可能会迟到。试试这件衣服。我之所以写这本书,是因为在其他方面缺乏这一特色。
http://iminuit.github.com/iminuit/
请参阅如何在此处编写通用成本函数的示例:
http://nbviewer.ipython.org/urls/raw.github.com/iminuit/iminuit/master/tutorial/hard-core-tutorial.ipynb
然而,尽管编写chi^2/似然函数很容易,但它已经在probfit 中为您编写了
http://iminuit.github.com/probfit/