1

在我的情况下,目标函数是一个数值过程,其中包含通过二分法对方程求根的过程。对于某些参数集,方程没有中间变量的根。我认为使二等分求根例程返回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)
4

1 回答 1

0

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

如果这是对您尝试做的事情的正确解释,那么最好对两者都设置界限a1a2这样目标函数就永远不会得到这些值。为此,curve_fit您需要为下限和上限创建一个数组元组,其顺序与您的匹配p0,所以

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

顺便说一句:我不知道您为什么使用 < 0 的起始值a1,因此超出范围。看来你是在自找麻烦。

为了更好地设置拟合参数的界限,您可以考虑使用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

希望有帮助。

于 2018-05-28T14:08:29.190 回答