虽然xnx已经告诉你为什么
curve_fit
失败了,但我想提供一种不依赖于梯度下降(因此需要合理的初始猜测)来解决拟合函数形式问题的不同方法。
请注意,如果您对要拟合的函数取对数,则会得到以下形式:
![\log f = \log A + \alpha \log x + B x](https://istack.dev59.com/bf7UI.webp)
其中每个未知参数(log A、alpha、B)都是线性的。
因此,我们可以使用线性代数的工具来通过将方程写成矩阵的形式来解决这个问题:
log y = M p
其中log y是您的ydata点的对数列向量,p是未知参数的列向量,M是矩阵
[[1], [log x], [x]]
。
或者明确地表达为:
![enter image description here](https://istack.dev59.com/eG2iC.webp)
然后可以通过使用
np.linalg.lstsq
高效地找到最佳拟合参数向量。
因此,您的示例问题的代码可以编写为:
import numpy as np
def func(x, A, B, alpha):
return A * x**alpha * np.exp(B * x)
A_true = 0.004
alpha_true = -0.75
B_true = -2*10**-8
xdata = np.linspace(1, 10**8, 1000)
ydata = func(xdata, A_true, B_true, alpha_true)
M = np.vstack([np.ones(len(xdata)), np.log(xdata), xdata]).T
logA, alpha, B = np.linalg.lstsq(M, np.log(ydata))[0]
print "A =", np.exp(logA)
print "alpha =", alpha
print "B =", B
这样可以很好地恢复初始参数:
A = 0.00400000003736
alpha = -0.750000000928
B = -1.9999999934e-08
还要注意的是,这种方法比使用curve_fit
在手头问题上快大约20倍。
In [8]: %timeit np.linalg.lstsq(np.vstack([np.ones(len(xdata)), np.log(xdata), xdata]).T, np.log(ydata))
10000 loops, best of 3: 169 µs per loop
In [2]: %timeit curve_fit(func, xdata, ydata, [0.01, -5e-7, -0.4])
100 loops, best of 3: 4.44 ms per loop