对象函数可以返回带有某些参数的None,如何在Curvefit中收敛时跳过或避免?

时间:2018-05-28 06:08:34

标签: python curve-fitting numerical

在我的情况下,目标函数是一个数值过程,包含通过二分法的方程的根查找过程。 对于某些参数集,该等式没有中间变量的根。我认为使二分根发现例程返回None可以解决这个问题。 由于对象函数的一组日期由scipy.optimize.curve_fitp0进行回归,其间由此情况分隔,因此错误将停止该过程。

为了研究这个案例,我们展示了一个简化的案例。

import numpy as np

#Define object function:
def f(x,a1,a2):
    if a1 < 0:
        return None
    elif a2 < 0:
        return np.inf
    else:
        return a1 * x**2 + a2

#Making data:
x = np.linspace(-5,5,10)
i = 0
y = np.empty_like(x)
for xi in x:
    y[i] = f(xi,1,1)
    i += 1

import scipy.optimize as sp

para,pvoc = sp.curve_fit(f,x,y,p0=(-1,1))
#TypeError: unsupported operand type(s) for -: 'NoneType' and 'float'

para,pvoc = sp.curve_fit(f,x,y,p0=(1,-1))
#RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 600.

我也试过inf,但显然不行。 我应该返回什么才能继续curve_fit进程? 想象一下,它正试图收敛,curve_fit遇到这种情况时会发生什么。

额外的想法: 我尝试try...except...忽略错误,并模拟p0处于可解决范围内的情况,但会将无法解析的段传递给真正的拟合。

import numpy as np

def f(x,a1,a2):
    if a1 < 0:
        return None
    elif a1 < 2:
        return a1 * x**2 + a2
    elif a2 < 0:
        return np.inf
    else:
        return a1 * x**2 + a2

def ff(x,a1,a2):
    output = f(x,a1,a2)
    if output == None:
        return 0
    else:
        return output

x = np.linspace(-5,5,10)
i = 0
y = np.empty_like(x)
for xi in x:
    y[i] = f(xi,1,1)
    i += 1


import scipy.optimize as sp

#para,pvoc = sp.curve_fit(f,x,y,p0=(-1,1))
#TypeError: unsupported operand type(s) for -: 'NoneType' and 'float':
#para,pvoc = sp.curve_fit(f,x,y,p0=(1,-1))

try:
    para,pvoc = sp.curve_fit(f,x,y,p0=(-3,1))
except TypeError:
    pass

显然在融合过程中遇到了错误,并且已被报告并被排除在外。 如何继续curve_fit原始收敛方向? 即使我可以让步,我如何告诉curve_fit将最后一次尝试返回a1

另一方面,我尝试将此try... except...置于对象函数中,以便在出现错误时返回0。 结果就像我期望的那样:

para,pvoc = sp.curve_fit(ff,x,y,p0=(-3,1))

#OptimizeWarning: Covariance of the parameters could not be estimated
  category=OptimizeWarning)

1 个答案:

答案 0 :(得分:0)

我认为你想采取不同的方法。也就是说,您已编写目标函数以返回NoneInf,以便在a1a2的值超出范围时发出信号:a1<0并且a2<0不是目标函数的可接受值。

如果这是对您要做的事情的正确解释,最好在a1a2上放置边界,以便目标函数永远不会获得这些值。要使用curve_fit执行此操作,您需要为下限和上限创建一个数组元组,其顺序与p0匹配,因此

pout, pcov = sp.curve_fit(f, x, y, p0=(1, 1), bounds=([0, 0], [np.inpf, np.inf])

顺便说一句:我不知道为什么你使用的a1的起始值是&lt; 0,等超出范围。这似乎是你在寻找麻烦。

为了更好地设置拟合参数的界限,您可以考虑使用lmfit,这将允许您编写:

import numpy as np
from lmfit import Model

def f(x, a1, a2):
    return a1 * x**2 + a2

fmod = Model(f)

params = fmod.make_params(a1=1, a2=0.5)
params['a1'].min = 0
params['a2'].min = 0

x = np.linspace(-5, 5, 10)

np.random.seed(0)
y = f(x, 1, 1) + np.random.normal(size=len(x), scale=0.02)

result = fmod.fit(y, params, x=x)
print(result.fit_report())

将打印出来

[[Model]]
    Model(f)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 13
    # data points      = 10
    # variables        = 2
    chi-square         = 0.00374066
    reduced chi-square = 4.6758e-04
    Akaike info crit   = -74.9107853
    Bayesian info crit = -74.3056151
[[Variables]]
    a1:  0.99998038 +/- 7.6225e-04 (0.08%) (init = 1)
    a2:  1.01496025 +/- 0.01034565 (1.02%) (init = 0.5)
[[Correlations]] (unreported correlations are < 0.100)
    C(a1, a2) = -0.750

希望有所帮助。