我在拟合数据曲线时遇到了一些困难,但是却不知道出了什么问题。
在以前的工作中,我使用 numpy.linalg.lstsq 来拟合指数函数,而使用 scipy.optimize.curve_fit 来拟合Sigmoid函数。这次我希望创建一个脚本,让我可以指定各种函数,确定参数并测试其与数据的拟合情况。在这个过程中我注意到 Scipy 的
Excel趋势线与Numpy的
在以前的工作中,我使用 numpy.linalg.lstsq 来拟合指数函数,而使用 scipy.optimize.curve_fit 来拟合Sigmoid函数。这次我希望创建一个脚本,让我可以指定各种函数,确定参数并测试其与数据的拟合情况。在这个过程中我注意到 Scipy 的
leastsq
和 Numpy 的 lstsq
对于相同的数据和相同的函数提供了不同的答案。这个函数很简单,是 y = e^(l*x)
,且在 x=0
时有 y=1
的限制。Excel趋势线与Numpy的
lstsq
结果一致,但是由于Scipy的 leastsq
可以处理任何函数,因此最好弄清楚问题所在。import scipy.optimize as optimize
import numpy as np
import matplotlib.pyplot as plt
## Sampled data
x = np.array([0, 14, 37, 975, 2013, 2095, 2147])
y = np.array([1.0, 0.764317544, 0.647136491, 0.070803763, 0.003630962, 0.001485394, 0.000495131])
# function
fp = lambda p, x: np.exp(p*x)
# error function
e = lambda p, x, y: (fp(p, x) - y)
# using scipy least squares
l1, s = optimize.leastsq(e, -0.004, args=(x,y))
print l1
# [-0.0132281]
# using numpy least squares
l2 = np.linalg.lstsq(np.vstack([x, np.zeros(len(x))]).T,np.log(y))[0][0]
print l2
# -0.00313461628963 (same answer as Excel trend line)
# smooth x for plotting
x_ = np.arange(0, x[-1], 0.2)
plt.figure()
plt.plot(x, y, 'rx', x_, fp(l1, x_), 'b-', x_, fp(l2, x_), 'g-')
plt.show()
编辑 - 附加信息
以上的MWE只包含数据集的一个小样本。当拟合实际数据时,scipy.optimize.curve_fit曲线的R^2值为0.82,而与Excel计算得出的相同的numpy.linalg.lstsq曲线的R^2值为0.41。
np.linalg.lstsq
拟合指数函数一样只是一个快速而不精确的技巧,无法正确计算误差。这里有一些讨论(对我来说很难理解):http://mathworld.wolfram.com/LeastSquaresFittingExponential.html 如果你不想深入研究这个东西,我建议使用 scipy 的方法:它应该能够提供更好的拟合效果,并且你的结果将对所有函数保持一致。 - Jaimenp.linalg.lstsq
方法在低x值处过度加权y误差。你分享的链接和我找到的其他资源让我得出了另一种分析方法(使它棘手的是约束条件——所有的书都描述了y=ae^bx的方法而不是y=e^b*x),然而,这也产生了比迭代的scipy.optimize.leastsq
更糟糕的拟合曲线。 - StacyR