感谢大家的回复。这是总结它们的另一种尝试。如果我说了太多“显而易见”的事情,请原谅:我以前对最小二乘一无所知,所以一切对我来说都是新的。
非多项式插值
Polynomial interpolation 在给定n+1 数据点的情况下拟合度为n 的多项式,例如找到一个恰好通过四个给定点的立方。正如问题中所说,这不是我想要的——我有很多点并且想要一个小次数多项式(它只会近似拟合,除非我们很幸运)——但是因为有些答案坚持要讲,我应该提一下:)Lagrange polynomial、Vandermonde matrix等
什么是最小二乘法?
“最小二乘”是多项式拟合“好坏”的特定定义/标准/“度量”。 (还有其他的,但这是最简单的。)假设您正在尝试拟合多项式
p(x,y) = a + bx + cy + dx2 + ey2 + fxy
到一些给定的数据点(xi,yi,Zi)(其中“Zi”是问题中的“f(xi,yi)”)。使用最小二乘法的问题是找到“最佳”系数(a,b,c,d,e,f),使得最小化(保持“最小”)的是“残差平方和”,即
S = ∑i (a + bxi + cyi + dxi2 + eyi2 + fxiyi - Zi)2
理论
重要的想法是,如果您将 S 视为 (a,b,c,d,e,f) 的函数,那么 S 在其 gradient is 0 的某个点上是 minimized。这意味着例如∂S/∂f=0,即
∑i2(a + … + fxiyi - Zi)xiyi = 0
和 a、b、c、d、e 的类似方程。
请注意,这些只是 a...f 中的线性方程。所以我们可以使用Gaussian elimination 或the usual methods 中的任何一个来解决它们。
这仍然被称为“线性最小二乘法”,因为虽然我们想要的函数是一个二次多项式,但它在参数中仍然是线性的 (a,b,c,d,e,f )。请注意,当我们希望 p(x,y) 是 任意 函数 fj 的任何“线性组合”时,同样的事情也有效,而不仅仅是多项式 (= "单项式的线性组合")。
代码
对于单变量情况(当只有变量 x 时——fj 是单项式 xj),有 Numpy 的polyfit:
>>> import numpy
>>> xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> ys = [1.1, 3.9, 11.2, 21.5, 34.8, 51, 70.2, 92.3, 117.4, 145.5]
>>> p = numpy.poly1d(numpy.polyfit(xs, ys, deg=2))
>>> print p
2
1.517 x + 2.483 x + 0.4927
对于多元情况,或一般的线性最小二乘,有 SciPy。 As explained in its documentation,它采用值 fj(xi) 的矩阵 A。 (理论是它找到了 A 的Moore-Penrose pseudoinverse。)我们上面的例子涉及 (xi,yi,Zi ),拟合多项式意味着 fj 是单项式 x()y()。下面找到最佳二次(或任何其他次数的最佳多项式,如果您更改“degree = 2”线):
from scipy import linalg
import random
n = 20
x = [100*random.random() for i in range(n)]
y = [100*random.random() for i in range(n)]
Z = [(x[i]+y[i])**2 + 0.01*random.random() for i in range(n)]
degree = 2
A = []
for i in range(n):
A.append([])
for xd in range(degree+1):
for yd in range(degree+1-xd):
A[i].append((x[i]**xd)*(y[i]**yd)) #f_j(x_i)
c,_,_,_ = linalg.lstsq(A,Z)
j = 0
for xd in range(0,degree+1):
for yd in range(0,degree+1-xd):
print " + (%.2f)x^%dy^%d" % (c[j], xd, yd),
j += 1
打印
+ (0.01)x^0y^0 + (-0.00)x^0y^1 + (1.00)x^0y^2 + (-0.00)x^1y^0 + (2.00)x^1y^1 + (1.00)x^2y^0
所以它发现多项式是x2+2xy+y2+0.01。 [最后一项有时是 -0.01,有时是 0,这是意料之中的,因为我们添加了随机噪声。]
Python+Numpy/Scipy 的替代品是R 和计算机代数系统:Sage、Mathematica、Matlab、Maple。甚至 Excel 也能做到。 Numerical Recipes 讨论了我们自己实现它的方法(在 C、Fortran 中)。
担忧
- 它受到如何选择点的强烈影响。当我有
x=y=range(20) 而不是随机点时,它总是产生 1.33x2+1.33xy+1.33y2,这令人费解......直到我意识到因为我一直有x[i]=y[i],所以多项式是相同的:x2+2xy+y2 = 4x2 = (4/3 )(x2+xy+y2)。因此,重要的是仔细选择点以获得“正确的”多项式。 (如果可以选择,您应该选择 Chebyshev nodes 进行多项式插值;不确定最小二乘是否也是如此。)
-
过拟合:更高次的多项式总能更好地拟合数据。如果您将
degree 更改为 3 或 4 或 5,它仍然主要识别相同的二次多项式(系数为 0 用于更高阶项),但对于更大的阶数,它开始拟合更高阶多项式。但即使使用 6 次,取更大的 n(更多数据点而不是 20,比如 200)仍然符合二次多项式。因此,道德是避免过度拟合,这可能有助于获取尽可能多的数据点。
- 可能有numerical stability 的问题我不太明白。
- 如果您不需要多项式,则可以更好地拟合其他类型的函数,例如splines(分段多项式)。