Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 动态定义函数_Python_Numpy_Scipy - Fatal编程技术网

Python 动态定义函数

Python 动态定义函数,python,numpy,scipy,Python,Numpy,Scipy,我试图编写一个曲线拟合函数,返回最佳参数a、b和c,下面是一个简化的示例: import numpy import scipy from scipy.optimize import curve_fit def f(x, a, b, c): return x * 2*a + 4*b - 5*c xdata = numpy.array([1,3,6,8,10]) ydata = numpy.array([ 0.91589774, 4.91589774, 10.91589774,

我试图编写一个曲线拟合函数,返回最佳参数a、b和c,下面是一个简化的示例:

import numpy
import scipy
from scipy.optimize import curve_fit

def f(x, a, b, c):
    return x * 2*a + 4*b - 5*c

xdata = numpy.array([1,3,6,8,10])
ydata = numpy.array([  0.91589774,   4.91589774,  10.91589774,  14.91589774,  18.91589774])
popt, pcov = scipy.optimize.curve_fit(f, xdata, ydata)
这很好,但我想让用户有机会提供一些(或没有)参数a、b或c,在这种情况下,它们应该被视为常量,而不是估计值。如何编写
f
,使其仅适合用户未提供的参数

基本上,我需要用正确的参数动态地定义
f
。例如,如果用户知道
a
f
变为:

def f(x, b, c):
    a = global_version_of_a
    return x * 2*a + 4*b - 5*c
如果用户没有为相关参数提供参数,则将使用您在
=
符号右侧指定的任何参数:

e、 g.:
f(5,b=20)
将计算为
返回5*2*10+4*20-5*25

f(7)
将计算为
返回7*2*10+4*15-5*25
从中选择一页,您可以使用exec“动态”定义
函数:

import numpy as np
import scipy.optimize as optimize
import textwrap

funcstr=textwrap.dedent('''\
def func(x, {p}):
    return x * 2*a + 4*b - 5*c
''')
def make_model(**kwargs):
    params=set(('a','b','c')).difference(kwargs.keys())
    exec funcstr.format(p=','.join(params)) in kwargs
    return kwargs['func']

func=make_model(a=3, b=1)

xdata = np.array([1,3,6,8,10])
ydata = np.array([  0.91589774,   4.91589774,  10.91589774,  14.91589774,  18.91589774])
popt, pcov = optimize.curve_fit(func, xdata, ydata)
print(popt)
# [ 5.49682045]
注意这一行

func=make_model(a=3, b=1)
您可以传递任何您想要创建的参数。传递给
的参数使_model
成为
func
中的固定常数。剩下的任何参数都将成为自由参数,进行优化。曲线拟合将尝试拟合

例如,上面的a=3和b=1在
func
中成为固定常数。实际上,
exec
语句将它们放在
func
的全局命名空间中<因此,code>func
被定义为
x
和单个参数
c
的函数。注意
popt
的返回值是一个长度为1的数组,对应于剩余的自由参数
c


关于
textwrap.dedent
:在上面的示例中,不需要调用
textwrap.dedent
。但在“现实生活”脚本中,
funcstr
是在函数内部或更深的缩进级别定义的,
textwrap.dedent
允许您编写

def foo():
    funcstr=textwrap.dedent('''\
        def func(x, {p}):
            return x * 2*a + 4*b - 5*c
        ''')
而不是视觉上不吸引人的

def foo():
    funcstr='''\
def func(x, {p}):
    return x * 2*a + 4*b - 5*c
'''
有些人更喜欢

def foo():
    funcstr=(
        'def func(x, {p}):\n'
        '    return x * 2*a + 4*b - 5*c'
        )

但我发现单独引用每一行和添加显式EOL字符有点麻烦。但是,它确实为您节省了一个函数调用。

如果您想要一个基于
曲线拟合的简单解决方案,我建议您将函数封装在类中。最简单的例子:

import numpy
from scipy.optimize import curve_fit

class FitModel(object):
    def f(self, x, a, b, c):
        return x * 2*a + 4*b - 5*c

    def f_a(self, x, b, c):
        return self.f(x, self.a, b, c)

# user supplies a = 1.0
fitModel = FitModel()
fitModel.a = 1.0

xdata = numpy.array([1,3,6,8,10])
ydata = numpy.array([  0.91589774,   4.91589774,  10.91589774,  14.91589774,  18.91589774])
initial = (1.0,2.0)
popt, pconv = curve_fit(fitModel.f_a, xdata, ydata, initial)

为此,我通常使用lambda

user_b, user_c = get_user_vals()
opt_fun = lambda x, a: f(x, a, user_b, user_c)
popt, pcov = scipy.optimize.curve_fit(opt_fun, xdata, ydata)

已经有一个包可以执行此操作:

自述文件:

“LMfit py提供了最小二乘最小化例程和类 使用简单、灵活的方法来参数化 拟合数据。命名参数可以固定或自由保持 在拟合中调整,或保持在下限和上限之间。在 此外,可以将参数约束为简单的数学表达式 其他参数的表达式。”

如果有5个参数,这将开始变得混乱,我需要编写的函数数量会快速增加……基本问题是,但我在更深的缩进级别(在类内部)定义funcstr时遇到困难。它抛出缩进错误…还有一件事。传递其他变量怎么样,例如,如果“c”是一个数组,我需要作为全局变量传入,但不想将其包含在f的参数中?谢谢。如果我没听错,就把它传给
make\u model
:例如
func=make\u model(c=array)
。(它不会显示在
f
的参数中。但是,
f
可以访问它。)顺便说一句,最后一个示例不起作用,字符串之间缺少换行符。哦,是的,我不喜欢此方法的另一个原因…:)(感谢您捕捉到错误。)如果lambda使用numpy函数,这是否有效?我如何使opt_-fun调用动态(我希望用户在脚本顶部设置paramaters,在需要安装参数的地方设置为None)。
user_b, user_c = get_user_vals()
opt_fun = lambda x, a: f(x, a, user_b, user_c)
popt, pcov = scipy.optimize.curve_fit(opt_fun, xdata, ydata)