我在为一些数据拟合曲线方面遇到了一些麻烦,但在我出错的地方无法解决。
过去我用 numpy.linalg.lstsq 表示指数函数, scipy.optimize.curve_fit 表示sigmoid函数。这次我希望创建一个脚本,让我指定各种函数,确定参数并测试它们与数据的拟合。在这样做时,我注意到Scipy leastsq
和Numpy lstsq
似乎为同一组数据和相同的函数提供了不同的答案。该函数只是y = e^(l*x)
,受约束,y=1
位于x=0
。
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,而 numpy.linalg.lstsq 曲线与计算的曲线相同通过Excel,R ^ 2为0.41。
答案 0 :(得分:4)
您正在最小化不同的错误函数。
使用numpy.linalg.lstsq
时,最小化的错误函数是
np.sum((np.log(y) - p * x)**2)
而scipy.optimize.leastsq
最小化功能
np.sum((y - np.exp(p * x))**2)
第一种情况需要依赖变量和自变量之间的线性依赖关系,但解决方案是分析性的,而第二种情况可以处理任何依赖关系,但依赖于迭代方法。
单独注意,我现在无法测试,但使用numpy.linalg.lstsq
时,我不需要vstack
一行零,以下同样有效:
l2 = np.linalg.lstsq(x[:, None], np.log(y))[0][0]
答案 1 :(得分:1)
为了阐述Jaime的观点,数据的任何非线性变换都将导致不同的误差函数,从而导致不同的解决方案。这些将导致拟合参数的不同置信区间。因此,您有三个可能的标准用于做出决定:您希望最小化哪个错误,您希望哪些参数更有信心,最后,如果您使用拟合来预测某个值,哪个方法产生的错误更少预测值。分析和Excel中的数据表明,数据中的不同类型的噪声(例如,如果噪声函数缩放幅度,影响时间常数或是加性)会导致不同的解决方案选择。
我还要补充一点,虽然这个技巧“适用于”指数衰减为0,但它不能用于阻尼指数(上升或下降)的更一般(和常见)情况下,不能假设的值为0。