我试着把这个函数拟合到一些数据上:
但是当我用我的代码
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: Covariance of the parameters could not be estimated
输出:
在这个例子中,开始和结束应该接近500,但它们与我最初的猜测没有任何变化。
2条答案
按热度按时间kjthegm61#
警告(不是错误)
意味着拟合不能确定拟合参数的不确定性(方差)。
主要问题是模型函数
f
将参数start
和end
视为离散值--它们被用作函数形式变化的整数位置。scipy的curve_fit
(以及scipy.optimize
中的所有其他优化例程)假设参数是 * 连续 * 变量,而不是离散的。拟合过程将尝试在参数中采取小步骤(通常围绕机器精度)以获得残差相对于变量(雅可比矩阵)的数值导数。在值用作离散变量的情况下,这些导数将为零,并且拟合过程将不知道如何改变值以改进拟合。
它看起来像你试图拟合一个阶跃函数的一些数据。请允许我推荐尝试
lmfit
(https://lmfit.github.io/lmfit-py),它提供了一个更高级别的曲线拟合接口,并且有许多内置模型。例如,它包括一个StepModel
,它应该能够对您的数据进行建模。对于您的数据的轻微修改(以便它具有有限的步长),以下带有
lmfit
的脚本可以适应这样的数据:打印出一份报告
并生成x1c 0d1x的图
Lmfit有很多额外的功能。例如,如果要设置某些参数值的界限或使某些参数值不发生变化,可以执行以下操作:
如果您知道模型应该是
Step+Constant
并且常数应该是固定的,那么您也可以将模型修改为agxfikkp2#
这个答案太晚了,但是如果你想坚持使用scipy中的
curve_fit
,那么重写这个函数,使它不显式地依赖于start
和end
作为截止点,就可以完成这项工作。例如,if x < start, then -1
可以通过将x
移位start
并检查其符号来写入,即np.sign(x - start)
。然后就变成了为函数的每个条件编写单独的定义并将它们添加到单个函数中。上面的函数可以用
np.clip()
(限制数组中的值)更简洁地编写,它可以取代上面的布尔索引和替换。然后使用与OP中相同的方式构建的数据,我们得到系数(499.499,501.51)(非常接近(500,500)),图如下所示。