提问人:Gargantua 提问时间:7/10/2023 更新时间:7/10/2023 访问量:77
在图中显示lmfit-model中心的误差
Showing the error of lmfit-model center in plot
问:
我正在使用 python lmfit 包进行数据拟合。我正在查看几个峰值,并用伪 Voigt + 常数模型拟合它们。然后,我提取拟合峰的中心位置,并编译大约一百个这样的峰位置。然后绘制一百个位置,并用正弦波模型(也使用 lmfit)进行拟合。 我的问题是,我无法找到我需要的信息来显示从伪Voigt拟合中提取的峰值位置的不确定性。在许多类似的问题中,我遇到了 lmfit 包中也包含的 eval_uncertainty 函数,但我无法使用它来提取中心位置的置信区间,只能提取峰值振幅和 sigma 值的不确定性。
理想的结果如下图所示: 我试图实现的理想情况
我的当前图表如下所示: 当前图表
显然,我需要从散点图切换到误差线图,但我目前没有任何错误间隔可供使用。
以下是我能构建的最简单可行的“迷你”案例,同时仍然包括我原始的适合模型。我的原始数据大约是 100 个数据点,而不是 4 个,因此在这种较小情况下的正弦波不是“平滑”的,但这应该不会影响引入误差线的方法。
import numpy as np
import matplotlib.pyplot as plt
from lmfit.models import PseudoVoigtModel, ConstantModel, SineModel
def Voigt_app(x,y,a,b):
psvo_mod = PseudoVoigtModel(prefix='psvo_')
pars = psvo_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = (y[0]+y[1])/2))
mod = psvo_mod + con_mod
out = mod.fit(y, pars, x=x)
details = out.fit_report(min_correl=0.25)
return out, details
def Sin_app(x,y):
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
mod = sin_mod + con_mod
out = mod.fit(y,pars,x=x)
details = out.fit_report(min_correl=0.25)
return out, details
data = np.asarray(
[[14407.0 , 26989.0 , 31026.0 , 31194.0 , 31302.0 , 91996.0 , 112250.0 , 112204.0 , 113431.0 , 75097.0 , 55942.0 , 55826.0 , 56181.0 , 28266.0 , 14687.0],
[12842.0 , 13275.0 , 13581.0 , 13943.0 , 14914.0 , 20463.0 , 21132.0 , 21457.0 , 23308.0 , 32017.0 , 30808.0 , 30927.0 , 30337.0 , 21025.0 , 15216.0],
[15770.0 , 17677.0 , 19008.0 , 20911.0 , 25958.0 , 27984.0 , 28164.0 , 31161.0 , 33517.0 , 29430.0 , 28673.0 , 32725.0 , 28495.0 , 24527.0 , 25173.0],
[16299.0 , 20067.0 , 25102.0 , 34968.0 , 37757.0 , 44871.0 , 51347.0 , 60154.0 , 54985.0 , 53383.0 , 45776.0 , 40836.0 , 30816.0 , 27922.0 , 26066.0]])
a,b = 1932, 1947
centers = []
colors = ['red','black','green','blue']
fig, ax = plt.subplots()
for i in range(4):
ax.scatter(np.arange(15),data[i,:],label=f'data {i}',color=colors[i])
out, details = Voigt_app(x,data[i,:],a,b)
ax.plot(out.best_fit,label=f'fit {i}',color=colors[i])
centers.append(out.values['psvo_center'])
ax.set_title('Data points and pseudo-Voigt fits')
ax.legend()
fig, ax = plt.subplots()
ax.scatter(np.arange(4),centers,color='red',label='data')
out, details = Sin_app(np.arange(4),np.asarray(centers))
ax.plot(np.arange(4),out.best_fit,color='black',label='fit')
ax.set_title('Peak positions and sine-wave fit')
ax.legend()
由此,我想将第二张图中的散点图与误差线图切换为伪Voigt峰值位置的置信区间(“out.values['psvo_center']”)。
答:
以下是修改 Voigt_app 函数以执行此操作的方法:
def Voigt_app(x,y,a,b):
psvo_mod = PseudoVoigtModel(prefix='psvo_')
pars = psvo_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = (y[0]+y[1])/2))
mod = psvo_mod + con_mod
out = mod.fit(y, pars, x=x)
# Calculate the confidence interval for the fitted parameters
ci = lmfit.conf_interval(out, out)
print(lmfit.printfuncs.report_ci(ci))
# Extract the uncertainty for 'psvo_center'
center_err = (ci['psvo_center'][2][1] - ci['psvo_center'][1][1])/2
details = out.fit_report(min_correl=0.25)
return out, details, center_err
然后,您可以在绘制误差线时使用这些不确定性:
center_errs = []
for i in range(4):
out, details, center_err = Voigt_app(x, data[i,:], a, b)
# ...
center_errs.append(center_err)
# ...
ax.errorbar(np.arange(4), centers, yerr=center_errs, fmt='o', color='red', label='data')
评论
psvo_center
out.params['psvo_center'].stderr
conf_intervals
stderr
如果我正确理解了您的问题,您不仅要提取每个拟合的“psvo_center”参数的最佳拟合值,还要提取“psvo_center”的标准误差,然后将这些值用作拟合正弦振荡的数据。
如果这是正确的,我认为您要做的是通过将代码更改为stderr
centers = []
stderrs = [] # < new
colors = ['red','black','green','blue']
fig, ax = plt.subplots()
for i in range(4):
ax.scatter(np.arange(15),data[i,:],label=f'data {i}',color=colors[i])
out, details = Voigt_app(np.arange(15), data[i,:], a, b)
ax.plot(out.best_fit,label=f'fit {i}',color=colors[i])
centers.append(out.params['psvo_center'].value) # < new
stderrs.append(out.params['psvo_center'].stderr) # < new
然后,您可以使用它来制作误差线图
ax.errorbar(np.arange(4), centers, stderrs, color='red',label='data')
您可能还想使用它们来加权拟合到正弦函数,也许可以修改您的stderrs
Sin_App
def Sin_app(x, y, dely): # < new
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
mod = sin_mod + con_mod
out = mod.fit(y, pars, x=x, weights=1./dely) # < new
details = out.fit_report(min_correl=0.25)
return out, details
并用
out, details = Sin_app(np.arange(4), np.asarray(centers), np.asarray(stderrs))
对于您给出的 4 个示例数据集,标准误差的变化不是很大,因此不会产生太大差异。但随着您添加更多数据集,它可能会变得更加重要。在使用此“生产中”之前,您可能希望添加有效的检查(例如、不是和不)。stderr
None
0
对于“另一件事”,您可能还想计算正弦函数中的预测不确定性并绘制该范围。您的示例有 4 个正弦拟合变量,只有 4 个值,在这种情况下,结果是近乎完美的拟合,拟合正弦函数的不确定性小得离谱。因此,为了说明这种方法,我在下面的拟合中修复了参数。如果拟合超过4个峰曲线的结果,则没有必要这样做。但是,为了说明,
把你改成con_c
Sin_app
def Sin_app(x, y, dely):
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
pars['con_c'].vary = False # needed with only 4 (x,y) values
mod = sin_mod + con_mod
out = mod.fit(y, pars, x=x, weights=1./dely)
details = out.fit_report(min_correl=0.25)
delta_fit = out.eval_uncertainty(sigma=1) # < new
return out, details, delta_fit
然后绘制使用它的结果
out, details, delta_fit = Sin_app(np.arange(4), np.asarray(centers), np.asarray(stderrs))
ax.plot(np.arange(4),out.best_fit, 'o', color='black',label='fit')
ax.fill_between(np.arange(4),
out.best_fit-delta_fit, out.best_fit+delta_fit,
color="#D7D7D7")
ax.set_title('Peak positions and sine-wave fit')
ax.legend()
这导致了以下最终情节:
显示带有误差线的峰中心的“数据”、拟合值和拟合的 1-sigma 范围。
评论
result.errorbars
评论