python - scipy curve_fit 引发“OptimizeWarning:无法估计参数的协方差”
问题描述
我正在尝试将此函数拟合到一些数据:
但是当我使用我的代码时
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def f(x, start, end):
res = np.empty_like(x)
res[x < start] =-1
res[x > end] = 1
linear = np.all([[start <= x], [x <= end]], axis=0)[0]
res[linear] = np.linspace(-1., 1., num=np.sum(linear))
return res
if __name__ == '__main__':
xdata = np.linspace(0., 1000., 1000)
ydata = -np.ones(1000)
ydata[500:1000] = 1.
ydata = ydata + np.random.normal(0., 0.25, len(ydata))
popt, pcov = curve_fit(f, xdata, ydata, p0=[495., 505.])
print(popt, pcov)
plt.figure()
plt.plot(xdata, f(xdata, *popt), 'r-', label='fit')
plt.plot(xdata, ydata, 'b-', label='data')
plt.show()
我得到错误
OptimizeWarning:无法估计参数的协方差
输出:
在这个例子中, start 和 end 应该更接近 500,但与我最初的猜测相比,它们根本没有变化。
解决方案
的警告(不是错误)
OptimizeWarning: Covariance of the parameters could not be estimated
意味着拟合无法确定拟合参数的不确定性(方差)。
主要问题是您的模型函数f
将参数start
和end
离散值视为离散值——它们被用作函数形式变化的整数位置。scipy curve_fit
(以及 中的所有其他优化例程scipy.optimize
)假定参数是连续变量,而不是离散变量。
拟合过程将尝试在参数中采取小步骤(通常围绕机器精度)以获得残差相对于变量(雅可比行列式)的数值导数。对于用作离散变量的值,这些导数将为零,并且拟合过程将不知道如何更改值以改进拟合。
看起来您正在尝试为某些数据拟合阶跃函数。请允许我推荐尝试lmfit
(https://lmfit.github.io/lmfit-py),它提供了更高级别的曲线拟合接口,并具有许多内置模型。例如,它包括一个StepModel
应该能够为您的数据建模的。
对于您的数据的轻微修改(使其具有有限的步骤),以下脚本lmfit
可以适合此类数据:
#!/usr/bin/python
import numpy as np
from lmfit.models import StepModel, LinearModel
import matplotlib.pyplot as plt
np.random.seed(0)
xdata = np.linspace(0., 1000., 1000)
ydata = -np.ones(1000)
ydata[500:1000] = 1.
# note that a linear step is added here:
ydata[490:510] = -1 + np.arange(20)/10.0
ydata = ydata + np.random.normal(size=len(xdata), scale=0.1)
# model data as Step + Line
step_mod = StepModel(form='linear', prefix='step_')
line_mod = LinearModel(prefix='line_')
model = step_mod + line_mod
# make named parameters, giving initial values:
pars = model.make_params(line_intercept=ydata.min(),
line_slope=0,
step_center=xdata.mean(),
step_amplitude=ydata.std(),
step_sigma=2.0)
# fit data to this model with these parameters
out = model.fit(ydata, pars, x=xdata)
# print results
print(out.fit_report())
# plot data and best-fit
plt.plot(xdata, ydata, 'b')
plt.plot(xdata, out.best_fit, 'r-')
plt.show()
打印出一份报告
[[Model]]
(Model(step, prefix='step_', form='linear') + Model(linear, prefix='line_'))
[[Fit Statistics]]
# fitting method = leastsq
# function evals = 49
# data points = 1000
# variables = 5
chi-square = 9.72660131
reduced chi-square = 0.00977548
Akaike info crit = -4622.89074
Bayesian info crit = -4598.35197
[[Variables]]
step_sigma: 20.6227793 +/- 0.77214167 (3.74%) (init = 2)
step_center: 490.167878 +/- 0.44804412 (0.09%) (init = 500)
step_amplitude: 1.98946656 +/- 0.01304854 (0.66%) (init = 0.996283)
line_intercept: -1.00628058 +/- 0.00706005 (0.70%) (init = -1.277259)
line_slope: 1.3947e-05 +/- 2.2340e-05 (160.18%) (init = 0)
[[Correlations]] (unreported correlations are < 0.100)
C(step_amplitude, line_slope) = -0.875
C(step_sigma, step_center) = -0.863
C(line_intercept, line_slope) = -0.774
C(step_amplitude, line_intercept) = 0.461
C(step_sigma, step_amplitude) = 0.170
C(step_sigma, line_slope) = -0.147
C(step_center, step_amplitude) = -0.146
C(step_center, line_slope) = 0.127
Lmfit 有很多额外的功能。例如,如果您想对某些参数值设置界限或修复一些变化,您可以执行以下操作:
# make named parameters, giving initial values:
pars = model.make_params(line_intercept=ydata.min(),
line_slope=0,
step_center=xdata.mean(),
step_amplitude=ydata.std(),
step_sigma=2.0)
# now set max and min values for step amplitude"
pars['step_amplitude'].min = 0
pars['step_amplitude'].max = 100
# fix the offset of the line to be -1.0
pars['line_offset'].value = -1.0
pars['line_offset'].vary = False
# then run fit with these parameters
out = model.fit(ydata, pars, x=xdata)
如果您知道模型应该是Step+Constant
并且常数应该是固定的,您还可以将模型修改为
from lmfit.models import ConstantModel
# model data as Step + Constant
step_mod = StepModel(form='linear', prefix='step_')
const_mod = ConstantModel(prefix='const_')
model = step_mod + const_mod
pars = model.make_params(const_c=-1,
step_center=xdata.mean(),
step_amplitude=ydata.std(),
step_sigma=2.0)
pars['const_c'].vary = False
推荐阅读
- html - 调整屏幕大小时更改 div 元素的大小
- ios - “数据计数”iOS的Tensorflow解释器抛出错误
- python - Powershell - 将两条管道合二为一
- javascript - react material-ui CardMedia组件中的自动播放视频
- python - 如何摆脱电报机器人中盘旋的小丑蛙?
- csv - 下载 .CSV 文件时,缺少 CRLF 换行符,但 Excel 可以正常加载。我可以在不加载 Excel 的情况下修复 CRLF 吗?
- arrays - C中的二维字符串数组:
- java - BigInteger 操作的运行时?
- java - 如何保存由错误登录引发的错误
- node.js - 如何在节点退出时发送邮件