Python 为什么Scipy如此不适合这条曲线?
我正在尝试使此函数适合某些数据 这是我的职责:Python 为什么Scipy如此不适合这条曲线?,python,scipy,Python,Scipy,我正在尝试使此函数适合某些数据 这是我的职责: def first_deriv(xlist, L, k, x0): return [k*L*(math.e**(-k*(x+x0)))/(1+math.e**(-k*(x+x0)))**2 for x in xlist] 这就是函数的外观,所以我希望得到一个非常好的拟合。 这是使函数适合数据的代码 popt = curve_fit(first_deriv, list(range(len(data))), data, bounds=((0
def first_deriv(xlist, L, k, x0):
return [k*L*(math.e**(-k*(x+x0)))/(1+math.e**(-k*(x+x0)))**2 for x in xlist]
这就是函数的外观,所以我希望得到一个非常好的拟合。
这是使函数适合数据的代码
popt = curve_fit(first_deriv, list(range(len(data))), data, bounds=((0, -np.inf, -np.inf), (10**(9), +np.inf, 0)), maxfev=10000)
我就是这样画的:
xdata = list(np.linspace(-100, 100, 2000))
plt.scatter(xdata, first_deriv(xdata, popt[0][0], popt[0][1], popt[0][2]), s=1)
边界的存在使得答案合理,但即使我将所有边界设为无限,它仍然给出了一个可怕的拟合
这太不合身了
我很惊讶曲线拟合似乎完全搞砸了。
有人能解释一下原因吗?优化过程可能会陷入局部极大值(当参数的任何更改首先会使拟合变得更差,然后再变得更好)。为了避免此问题(并加快计算),允许您使用
p0
关键字参数指定参数的最佳猜测
因此,您应该将用于上述函数绘图的参数值作为起点传递到
曲线拟合()
。您的示例存在两个问题
一个小问题
curve\u fit
需要的是,而上面的代码给出的是列表(范围(len(data))
,它将产生从0到数据
长度的整x值。您会注意到散点图点只会上升到~50。我猜这就是原因
相反,您应该给出观察到数据
点的自变量值列表。根据数据
的生成/收集方式(您的问题中没有提供此信息),这可能是扩展数据
对于第二个图如何与第一个图相匹配,我也有点困惑。y刻度似乎与蓝线不匹配。我猜这些图是根据不同参数值的不同示例生成的。我将忽略它们
真正的问题
并非所有优化方法都同样适用于所有问题。曲线拟合
能够使用三种方法,'lm
、'trf'
和'dogbox'
。默认值为lm
,除非给出了边界,否则在这种情况下,将使用'trf'
,这是一种方法
稍微玩弄一下这个例子,我发现'lm'
表现得很好,而'trf'
则没有
例如,以以下代码为例:
import math
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def first_deriv(xlist, L, k, x0):
return [k*L*(math.e**(-k*(x+x0)))/(1+math.e**(-k*(x+x0)))**2 for x in xlist]
xdata = list(np.linspace(-100, 100, 2000))
real_parameters = (320000.0, 0.1, -30.0)
fakedata = first_deriv(xdata, *real_parameters)
plt.plot(xdata, fakedata)
这将生成上面示例中的曲线(ish):
通过对这三种方法的比较,可以确认'lm'
看起来是最好的,并恢复了原始参数:
lm_parameters = curve_fit(first_deriv, xdata, fakedata)[0]
trf_parameters = curve_fit(first_deriv, xdata, fakedata, method='trf')[0]
dogbox_parameters = curve_fit(first_deriv, xdata, fakedata, method='dogbox')[0]
plt.scatter(xdata, first_deriv(xdata, *lm_parameters), s=1, label='lm')
plt.scatter(xdata, first_deriv(xdata, *trf_parameters), s=1, label='trf')
plt.scatter(xdata, first_deriv(xdata, *dogbox_parameters), s=1, label='dogbox')
plt.legend()
一个有趣的问题(可能值得发表自己的帖子)是为什么会这样。虽然我没有资格进行精确的数学论证,但玩弄函数的参数却暗示了一些粗略的想法
例如,函数的“加宽峰值”似乎允许所有方法都能很好地执行。
毫无疑问,改变参数改变了“适应度景观”,使信赖域方法得以成功
'trf'
和'dogbox'
方法本身的某些参数也可能产生更好的结果。这需要对这些方法有更深入的了解
话虽如此,
'lm'
似乎是解决此特定问题的最佳方法。了解您使用的方法,并针对每个新问题尝试不同的方法,这一点始终很重要,特别是如果您得到的结果不好。什么是数据
变量?它是如何生成的?我无法运行您的cod如上所述,也许你可以提供一个MWE-你正在传递一组不同的x值到拟合与绘图…初始猜测在这里非常重要。对于高斯分布,我推荐Jean-Jacquelin的方法。是的,肯定比我在这里写的要多得多。在这种情况下,lm似乎可以很好地处理默认的初始猜测,虽然在其他情况下使用不同的初始猜测会有好处,但我敢肯定。它应该有自己的帖子,我想非常感谢!