感谢大家的回复。这是总结它们的另一种尝试。如果我说了太多“显而易见”的事情,请原谅:我以前对最小二乘一无所知,所以一切对我来说都是新的。
非多项式插值
多项式插值拟合n
给定n+1
数据点的度数多项式,例如找到精确通过四个给定点的三次方。正如问题中所说,这不是我想要的——我有很多点并且想要一个小次数多项式(除非我们很幸运,否则它只会近似拟合)——但由于一些答案坚持谈论关于它,我应该提到它们 :)拉格朗日多项式、范德蒙德矩阵等。
什么是最小二乘?
“最小二乘”是多项式拟合“有多好”的特定定义/标准/“度量”。(还有其他的,但这是最简单的。)假设您试图将多项式 p(x,y) = a + bx + cy + dx 2 + ey 2 + fxy 拟合到某些给定的数据点 (x i ,y i ,Z i )(其中“Z i ”在问题中是“f(x i ,y i )”)。使用最小二乘法的问题是找到“最佳”系数(a,b,c,d,e,f),使得最小化(保持“最小”)的是“残差平方和”,即
S = ∑ i (a + bx i + cy i + dx i 2 + ey i 2 + fx i y i - Z i ) 2
理论
重要的想法是,如果您将 S 视为 (a,b,c,d,e,f) 的函数,则 S在其梯度为 0的点处被最小化。这意味着例如∂S/∂f=0,即
∑ i 2(a + … + fx i y i - Z i )x i y i = 0
以及 a、b、c、d、e 的类似方程。请注意,这些只是 a...f 中的线性方程。所以我们可以用高斯消元法或任何常用方法来解决它们。
这仍然被称为“线性最小二乘法”,因为虽然我们想要的函数是二次多项式,但它在参数(a,b,c,d,e,f) 中仍然是线性的。请注意,当我们希望 p(x,y) 是任意函数 f j的任何“线性组合” ,而不仅仅是多项式(=“单项式的线性组合”)时,同样的事情也有效。
代码
对于单变量情况(当只有变量 x - f j是单项式 x j时),有 Numpy's 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。如其文档中所述,它采用值 f j ( x i )的矩阵 A。(理论是它找到 A 的Moore-Penrose 伪逆。)在我们上面涉及 (x i ,y i ,Z i ) 的示例中,拟合多项式意味着 f j是单项式 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
所以它发现多项式是x 2 +2xy+y 2 +0.01。[最后一项有时为 -0.01,有时为 0,这是可以预料的,因为我们添加了随机噪声。]
Python+Numpy/Scipy 的替代品是R和计算机代数系统:Sage、Mathematica、Matlab、Maple。甚至 Excel 也能做到。Numerical Recipes讨论了我们自己实现它的方法(在 C、Fortran 中)。
关注点
- 它受到如何选择点的强烈影响。当我有
x=y=range(20)
而不是随机点时,它总是产生 1.33x 2 +1.33xy+1.33y 2,这令人费解......直到我意识到因为我总是有x[i]=y[i]
,所以多项式是相同的:x 2 +2xy+y 2 = 4x 2 = (4/3)(x 2 +xy+y 2 )。因此,重要的是仔细选择点以获得“正确的”多项式。(如果可以选择,您应该选择Chebyshev 节点进行多项式插值;不确定最小二乘是否也是如此。)
- 过度拟合:更高次的多项式总是可以更好地拟合数据。如果将 更改
degree
为 3 或 4 或 5,它仍然主要识别相同的二次多项式(系数为 0 表示更高阶项),但对于更大的阶数,它开始拟合更高阶多项式。但即使使用 6 次,取更大的 n(更多数据点而不是 20,比如 200)仍然适合二次多项式。因此,道德是避免过度拟合,这可能有助于获取尽可能多的数据点。
- 可能存在我不完全理解的数值稳定性问题。
- 如果您不需要多项式,则可以更好地拟合其他类型的函数,例如样条(分段多项式)。