为什么 Scipy 如此糟糕地拟合这条曲线?

use*_*757 1 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]
Run Code Online (Sandbox Code Playgroud)

这就是函数的样子,所以我希望得到一个非常好的拟合。 该函数的外观如何

这是使函数适合数据的代码

popt = curve_fit(first_deriv, list(range(len(data))), data, bounds=((0, -np.inf, -np.inf), (10**(9), +np.inf, 0)), maxfev=10000)
Run Code Online (Sandbox Code Playgroud)

这就是我绘制它的方式:

xdata = list(np.linspace(-100, 100, 2000))    
plt.scatter(xdata, first_deriv(xdata, popt[0][0], popt[0][1], popt[0][2]), s=1)
Run Code Online (Sandbox Code Playgroud)

界限的存在是为了使答案合理,但即使我将所有界限设为无限,它仍然给出了一个糟糕的拟合。

这是可怕的拟合

不合适

我很惊讶 curve_fit 似乎完全搞砸了。有人可以解释一下为什么吗?

L.G*_*ger 6

你的例子有两个问题。

\n\n

一个小问题

\n\n

curve_fit期望自变量的值作为第二个参数,而上面的代码给出list(range(len(data)),它将产生从 0 到任意长度的整数 x 值data。您会注意到散点图点最多只能达到约 50 个。我的猜测是这就是原因。

\n\n

data相反,您应该给出观察点处自变量值的列表。根据data生成/收集的方式(您没有在问题中提供此信息),这可能是xdata.

\n\n

我也有点困惑第二个情节如何与第一个情节相适应。y 比例似乎与蓝线不匹配。我的猜测是,这些图是根据不同参数值的不同示例生成的。我会忽略他们。

\n\n

真正的问题

\n\n

并非所有优化方法都同样适合所有问题。curve_fit能够使用 3 种方法,\'lm\'trf\'\'dogbox\'lm对于Levenberg\xe2\x80\x93Marquardt 方法,默认值为,除非给出边界\'trf\',在这种情况下将使用信任区域方法

\n\n

稍微玩了一下这个例子,我发现\'lm\'表现良好,而表现\'trf\'不佳。

\n\n

例如,采用以下代码:

\n\n
import math\nimport numpy as np\nfrom scipy.optimize import curve_fit\nimport matplotlib.pyplot as plt\n\ndef first_deriv(xlist, L, k, x0):\n    return [k*L*(math.e**(-k*(x+x0)))/(1+math.e**(-k*(x+x0)))**2 for x in xlist]\n\nxdata = list(np.linspace(-100, 100, 2000))\nreal_parameters = (320000.0, 0.1, -30.0)\n\nfakedata = first_deriv(xdata, *real_parameters)\nplt.plot(xdata, fakedata)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这会产生上面示例中的曲线(ish):\n在此输入图像描述

\n\n

三种方法的比较确认了\'lm\'看起来最好,并恢复了原始参数:

\n\n
lm_parameters = curve_fit(first_deriv, xdata, fakedata)[0]\ntrf_parameters = curve_fit(first_deriv, xdata, fakedata, method=\'trf\')[0]\ndogbox_parameters = curve_fit(first_deriv, xdata, fakedata, method=\'dogbox\')[0]\n\nplt.scatter(xdata, first_deriv(xdata, *lm_parameters), s=1, label=\'lm\')\nplt.scatter(xdata, first_deriv(xdata, *trf_parameters), s=1, label=\'trf\')\nplt.scatter(xdata, first_deriv(xdata, *dogbox_parameters), s=1, label=\'dogbox\')\nplt.legend()\n
Run Code Online (Sandbox Code Playgroud)\n\n

在此输入图像描述

\n\n

一个有趣的问题(也许值得单独发表一篇文章)是为什么会出现这种情况。虽然我没有资格进行精确的数学论证,但使用函数的参数可以得出一些粗略的想法。

\n\n

例如,“扩大函数的峰值”似乎可以让所有方法都表现良好。\n在此输入图像描述\n在此输入图像描述

\n\n

毫无疑问,改变参数已经改变了“适应度景观”,使得信任域方法能够成功。

\n\n

\'trf\'和方法本身的某些参数也可能\'dogbox\'产生更好的结果。这需要对这些方法有更深入的了解。

\n\n

话虽如此,\'lm\'这似乎是解决这个特定问题的最佳方法。了解您正在使用哪种方法并针对每个新问题尝试不同的方法始终很重要,尤其是当您得到不好的结果时。

\n