当只有水平误差条时利用 scipy.odr 模块寻找最佳参数时的收敛

Convergence when utilizing scipy.odr module to find best-fit parameters when there is only horizontal errorbars

我正在尝试将分段(否则为线性)函数拟合到一组实验数据。数据的形式是只有水平误差线而没有垂直误差线。我熟悉 scipy.optimize.curve_fit 模块,但是当只有与 因变量 y 对应的垂直误差条时,它才有效。在搜索我的特定需求后,我遇到了以下 post,其中解释了当误差线是 自变量 x 的误差线时使用 scipy.odr 模块的可能性。 (Correct fitting with scipy curve_fit including errors in x?)

附件是我的代码版本,它尝试使用 ODR 方法找到最合适的参数。它实际上绘制了 best-fit 函数并且看起来它正在工作。但是,在更改初始(有根据的猜测)值并尝试提取最合适的参数后,我得到了与最初插入的相同的猜测参数。这意味着该方法不收敛,您可以通过打印 output.stopreason 并获得

来验证这一点

['Numerical error detected']

所以,我的问题是这种方法是否与我的分段函数一致,如果不一致,在这种情况下是否还有其他正确的方法可以采用?

from numpy import *
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
from scipy.odr import ODR, Model, Data, RealData

x_array=array([8.2,8.6,9.,9.4,9.8,10.2,10.6,11.,11.4,11.8])
x_err_array=array([0.2]*10)
y_array=array([-2.05179545,-1.64998354,-1.49136169,-0.94200805,-0.60205999,0.,0.,0.,0.,0.])
y_err_array=array([0]*10)


# Linear Fitting Model
def func(beta, x):
    return piecewise(x, [x < beta[0]], [lambda x:beta[1]*x-beta[1]*beta[0], lambda x:0.0])

data  = RealData(x_array, y_array, x_err_array, y_err_array)
model = Model(func)

odr = ODR(data, model, [10.1,1.02])
odr.set_job(fit_type=0)
output = odr.run()

f, (ax1) = plt.subplots(1, sharex=True, sharey=True, figsize=(10,10))

ax1.errorbar(x_array, y_array, xerr = x_err_array, yerr = y_err_array, ecolor = 'blue', elinewidth = 3, capsize = 3, linestyle = '')
ax1.plot(x_array, func(output.beta, x_array), 'blue',  linestyle = 'dotted', label='Best-Fit')

ax1.legend(loc='lower right', ncol=1, fontsize=12)
ax1.set_xlim([7.95, 12.05])
ax1.set_ylim([-2.1, 0.1])
ax1.yaxis.set_major_locator(MaxNLocator(prune='upper')) 
ax1.set_ylabel('$y$', fontsize=12)
ax1.set_xlabel('$x$', fontsize=12)
ax1.set_xscale("linear", nonposx='clip')
ax1.set_yscale("linear", nonposy='clip')
ax1.get_xaxis().tick_bottom()  
ax1.get_yaxis().tick_left()

f.subplots_adjust(top=0.98,bottom=0.14,left=0.14,right=0.98)
plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=True)
plt.show()

y 的错误 0 导致了问题。使其变小但不为零,例如1e-16。这样做会收敛拟合。如果您在定义 RealData 时省略 y_err_array 也会发生这种情况,但我不确定在这种情况下内部会发生什么。