如何在Python中的scipy.optimize.curve_fit中设置变量参数?

时间:2018-01-19 21:07:53

标签: python scipy variadic-functions curve-fitting

我正在使用scioy.optimize.curve_fit在Python中执行优化问题。 curve_fit函数将输入视为curve_fit(f,xdata,ydata,...),其中f callable是模型函数f(x,...)。它必须将自变量作为第一个参数,并将参数作为单独的剩余参数。

但是,在我的情况下,其余的参数是可变的。例如,f可以是f = fun(indepent_var,a,b,c,d),或f = fun(indepent_var,a,c,d)。

f的实际参数由用户在解决优化问题时定义。例如,一个用户可能想要使用a,b,c,d作为参数,而另一个用户想要使用a,c,d,而第三个用户可能使用b,c。然后,我的问题是如何在f中设置变量参数,然后用户可以配置自己的参数?

def func(data, a, b, c, d):
    return a * np.exp(-b * data) + c        

#def func(data, a, c, d):
#    return a * np.exp(-c * x)

popt, pcov = curve_fit(func, xdata, ydata)

"config_1.ini"
params_to_be_optimized = a, b, c, d

"config_2.ini"
params_to_be_optimized = a, c, d

我正在尝试做这样的事情:

def func(data, **kwards):
    a = kwargs['a'] if a in kwargs else 0
    ...
    return ...

popt, pcov = curve_fit(lambda(...), xdata, ydata)

但我不确切知道如何解决问题。我认为lambda功能可能有效,但是有人可以给我一个例子吗?

2 个答案:

答案 0 :(得分:2)

使用datetime_object = datetime.now()文档中的示例:

curve_fit

没有In [260]: def func(x, a, b, c): ...: return a * np.exp(-b * x) + c ...: In [261]: xdata = np.linspace(0, 4, 50) ...: y = func(xdata, 2.5, 1.3, 0.5) ...: np.random.seed(1729) ...: y_noise = 0.2 * np.random.normal(size=xdata.size) ...: ydata = y + y_noise 参数,拟合参数的数量由内省决定,即检查p0代码和属性

func

在这种情况下,它识别3个参数:

p0 : None, scalar, or N-length sequence, optional

Initial guess for the parameters. If None, then the initial values will all be 1 (if the number of parameters for the function can be determined using introspection, otherwise a ValueError is raised).

我可以使用In [263]: optimize.curve_fit(func, xdata, ydata) Out[263]: (array([ 2.55423706, 1.35190947, 0.47450618]), array([[ 0.0158905 , 0.00681778, -0.0007614 ], [ 0.00681778, 0.02019919, 0.00541905], [-0.0007614 , 0.00541905, 0.00282595]])) 来定义等效函数:

*args

但如果我试图适应它,我会收到一个错误:

In [264]: def f1(x, *args):
     ...:     return func(x, *args)
     ...: 

但我可以指定In [266]: optimize.curve_fit(f1, xdata, ydata) ValueError: Unable to determine number of fit parameters.

p0

如果我提供其他In [268]: optimize.curve_fit(f1, xdata, ydata, p0=np.ones(3)) Out[268]: (array([ 2.55423706, 1.35190947, 0.47450618]), ....) 尺寸,我会收到错误,因为p0将其参数传递给f1。我可以定义func,因此它更容忍其他args数字,但我可能会得到f1

答案 1 :(得分:2)

这可能不是一个完整的答案,但对于评论来说太长了。 当然,提供一个更具体的例子来说明你要做的事情肯定会有助于澄清你的问题并获得更好的答案。

我并不完全清楚你的函数的签名是什么,但可能是基本的问题是如何让用户在有其他参数时选择哪个函数参数成为变量中的变量成为变量,要么保留在某个固定值,要么被用作实际使用的功能形式的开关(这似乎是您的澄清评论试图说的)。

在任何一种情况下,您都可能会发现lmfit(https://lmfit.github.io/lmfit-py/)很有用。它有一个Model类,它支持基于scipy.optimize的曲线拟合,但与curve_fit分开(并且稍高于)lmfit.Modeldef func(x, a=1, b=2, c=3, d=0, option=True): if option: return a * np.exp(-b*x) + c + d*x else: return a * np.exp(-b*x**2) + c + d*x 可以转换任何"模型功能"进入可用于拟合数据的模型,并使用检查将函数参数转换为拟合中使用的参数。任何参数都可以是变量或固定的(或者具有边界或由简单的约束表达式设置),这可能是您正在寻找的:用户可以决定某些函数参数不适合变量

此外,如果模型函数的关键字参数不具有数字默认值,则它们不会成为拟合变量,但可以用作可选开关,可能控制所使用的函数形式。也就是说,如果你有像

这样的模型函数
from lmfit impor Model
mymodel = Model(func)
params = mymodel.make_params(a=100, b=-1, c=0, d=0)

然后您可以使用

创建拟合模型和参数
d

然后(例如)将params['d'].value = 0 params['d'].vary = False 修复为0:

option

或应用其他起始值,界限等。

要更改mymodel.fit()参数的值,您可以将其视为另一个独立变量,将其作为关键字参数传递给mymodel.eval()xdata = <array of data> ydata = <array of data> result = mymodel.fit(ydata, params, x=xdata, option=False) print(result.fit_report()) ,如下所示:

**kws

这将允许用户选择模型函数中使用的选项。

希望指出你正确的方向......

更新问题后:

通常,支持def func(data, **kwargs): a = kwargs['a'] if a in kwargs else 0 ... 会非常困难:用户可以将任何内容传递给此dict,以及如何在函数中使用它是未知的。例如,拟合变量必须是浮点数。但是,您可能也认识到了

def func(data, a=0, **kwargs):
    ...

可以重列为

def func(x, a=1, b=2, c=3, d=0):
     ...

# read from "config_1.ini"
params_to_be_optimized = 'a', 'b', 'c', 'd'

# read from "config_2.ini"
params_to_be_optimized = 'a', 'c', 'd'

支持此 。这意味着你必须为可能是变量的所有数量显式地创建函数参数,但这不应该太难。一旦完成,用户可以决定哪一个实际上在特定的适合变化。

你绝对可以使用像

这样的东西
mymodel = Model(func)
params = mymodel.make_params()   

for parname, param in params.items():
    param.vary = parname in params_to_be_optimized

等等

include_once 'class.os.php';
include_once 'function.filesize.32bit.php';

// Must be real path to file
$file = "/home/username/some-folder/yourfile.zip";
echo get_filesize($file);

控制哪些参数将被优化以及哪些参数将被修复。