将多项式拟合到数据

时间:2008-12-19 20:59:01

标签: math statistics

在给定一组值(x,f(x))的情况下,是否有办法找到最适合数据的给定度数的多项式?

我知道polynomial interpolation,用于查找给定n个数据点的n+1度的多项式,但这里有大量值,我们希望找到一个低值度多项式(找到最佳线性拟合,最佳二次,最佳立方等)。它可能与least squares ...

有关

更一般地说,我想知道答案,当我们有一个多变量函数 - 像(x,y,f(x,y))之类的点,比如说 - 并希望找到给定度数的最佳多项式(p(x,y))在变量中。 (特别是多项式,而不是样条或傅里叶级数。)

理论和代码/库(最好是Python,但任何语言都没问题)都很有用。

10 个答案:

答案 0 :(得分:56)

感谢大家的回复。这是另一种总结它们的尝试。请原谅,如果我说太多“明显”的事情:我之前对最小二乘法一无所知,所以对我来说一切都是新的。

非多项式插值

Polynomial interpolation拟合给定n个数据点的n+1度的多项式,例如找到一个完全通过四个给定点的立方体。正如在问题中所说,这不是我想要的 - 我有很多要点并且想要一个小程度多项式(只有大约适合,除非我们很幸运) - 但是一些答案坚持谈论它,我应该提到它们:) Lagrange polynomialVandermonde matrix等。

什么是最小二乘?

“最小二乘法”是多项式拟合“有多好”的特定定义/标准/“度量”。 (还有其他人,但这是最简单的。)假设您正在尝试拟合多项式 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),使得最小化(保持“最小”)的是“残差平方和”,即< / p>

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 minimized处于gradient的某一点。 is 0。这意味着例如∂S/∂f= 0,即

Σ i 2(a + ... + fx i y i - Z i )x i y i = 0

和a,b,c,d,e的类似方程式。 请注意,这些只是... f中的线性方程式。因此,我们可以使用Gaussian elimination或任何the usual methods来解决这些问题。

这仍称为“线性最小二乘法”,因为虽然我们想要的函数是二次多项式,但它仍然是参数中的线性(a,b,c,d,e,f )。注意,当我们希望p(x,y)是任意函数f j 的任何“线性组合”时,同样的事情是有效的,而不仅仅是一个多项式(=“单项式的线性组合“)。

代码

对于单变量情况(当只有变量x - f j 是单项式x j )时,有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,它采用值f j x i )的矩阵A. (理论上它找到了A的Moore-Penrose pseudoinverse。)上面的例子涉及(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 nodes进行多项式插值;不确定最小二乘方是否也是如此。)
  • 过度拟合:更高次数的多项式总能更好地拟合数据。如果将degree更改为3或4或5,它仍然主要识别相同的二次多项式(高阶项的系数为0),但对于更大的度数,它开始拟合更高次多项式。但即使是6度,采用更大的n(更多的数据点而不是20,比如200)仍然适合二次多项式。因此,道德是避免过度拟合,为此可能有助于尽可能多地获取数据点。
  • 可能存在numerical stability我不完全理解的问题。
  • 如果您不需要多项式,则可以更好地适应其他类型的函数,例如: splines(分段多项式)。

答案 1 :(得分:7)

是的,通常这样做的方法是使用最小二乘法。还有其他方法可以指定多项式的拟合程度,但对于最小二乘法,理论最简单。一般理论称为线性回归。

最好的选择可能是从Numerical Recipes开始。

R是免费的,可以做你想做的一切,但是它有很大的学习曲线。

如果您可以访问Mathematica,则可以使用“拟合”功能进行最小二乘拟合。我想Matlab和它的开源对手Octave有类似的功能。

答案 2 :(得分:5)

对于(x,f(x))案例:

import numpy

x = numpy.arange(10)
y = x**2

coeffs = numpy.polyfit(x, y, deg=2)
poly = numpy.poly1d(coeffs)
print poly
yp = numpy.polyval(poly, x)
print (yp-y)

答案 3 :(得分:4)

请记住,更高程度的多项式总是更适合数据。更高程度的多项式通常导致非常不可能的函数(参见Occam's Razor),但是(过度拟合)。您希望在简单性(多项式次数)和拟合(例如最小平方误差)之间找到平衡点。从数量上来说,有Akaike Information CriterionBayesian Information Criterion的测试。这些测试给出了一个优先选择模型的分数。

答案 4 :(得分:2)

如果要将(xi,f(xi))拟合到度 n 的多项式,那么您将设置数据的线性最小二乘问题(1,xi,xi,xi ^ 2,...,xi ^ n,f(xi))。这将返回一组系数(c0,c1,... ,cn)以便最佳拟合多项式是* y = c0 + c1 * x + c2 * x ^ 2 + ... + cn * x ^ n。*

通过在问题中包含 y 以及 x y 的组合,可以概括这两个因变量。< / p>

答案 5 :(得分:2)

拉格朗日多项式(如张贴@j w)可以精确拟合您指定的点,但是如果多项式的度数大于5或6,则可能会遇到数值不稳定。

最小二乘法为您提供“最佳拟合”多项式,其误差定义为各个误差的平方和。 (取你所拥有的点之间的y轴距离和得到的函数,将它们平方,然后求它们)MATLAB polyfit函数执行此操作,并使用多个返回参数,您可以自动获取它处理缩放/偏移问题(例如,如果你在x = 312.1和312.3之间有100个点,并且你想要一个6度多项式,你将要计算u =(x-312.2)/0.1所以你-values分布在-1和+ =之间。

注意,x轴值的分布会影响最小二乘拟合的结果强烈。如果x值的间距相等,那么最终会得到更大的误差。如果您有一个案例,您可以选择 x值并且您关心与已知函数和插值多项式的最大偏差,那么Chebyshev polynomials的使用将为您提供一些东西。接近完美的minimax多项式(很难计算)。在Numerical Recipes中对此进行了详细讨论。

编辑:从我收集的内容来看,这一切都适用于一个变量的功能。对于多变量函数,如果学位超过2,那么可能要困难得多。我确实找到reference on Google Books

答案 6 :(得分:2)

在大学时我们有这本书,我仍然觉得非常有用:Conte,de Boor;初等数值分析; Mc Grow Hill。相关段落为6.2:数据拟合 示例代码来自FORTRAN,并且列表也不是非常易读,但同时解释深刻而清晰。你最终会理解你在做什么,而不仅仅是这样做(就像我对数字食谱的体验一样) 我通常从数字食谱开始,但对于这样的事情,我很快就要抓住Conte-de Boor。

也许最好发布一些代码...它有点被剥离,但最相关的部分就在那里。它显然依赖于numpy!

def Tn(n, x):
  if n==0:
    return 1.0
  elif n==1:
    return float(x)
  else:
    return (2.0 * x * Tn(n - 1, x)) - Tn(n - 2, x)

class ChebyshevFit:

  def __init__(self):
    self.Tn = Memoize(Tn)

  def fit(self, data, degree=None):
    """fit the data by a 'minimal squares' linear combination of chebyshev polinomials.

    cfr: Conte, de Boor; elementary numerical analysis; Mc Grow Hill (6.2: Data Fitting)
    """

    if degree is None:
      degree = 5

    data = sorted(data)
    self.range = start, end = (min(data)[0], max(data)[0])
    self.halfwidth = (end - start) / 2.0
    vec_x = [(x - start - self.halfwidth)/self.halfwidth for (x, y) in data]
    vec_f = [y for (x, y) in data]

    mat_phi = [numpy.array([self.Tn(i, x) for x in vec_x]) for i in range(degree+1)]
    mat_A = numpy.inner(mat_phi, mat_phi)
    vec_b = numpy.inner(vec_f, mat_phi)

    self.coefficients = numpy.linalg.solve(mat_A, vec_b)
    self.degree = degree

  def evaluate(self, x):
    """use Clenshaw algorithm

    http://en.wikipedia.org/wiki/Clenshaw_algorithm
    """

    x = (x-self.range[0]-self.halfwidth) / self.halfwidth

    b_2 = float(self.coefficients[self.degree])
    b_1 = 2 * x * b_2 + float(self.coefficients[self.degree - 1])

    for i in range(2, self.degree):
      b_1, b_2 = 2.0 * x * b_1 + self.coefficients[self.degree - i] - b_2, b_1
    else:
      b_0 = x*b_1 + self.coefficients[0] - b_2

    return b_0

答案 7 :(得分:0)

请记住,近似多项式与找到完全之间存在很大差异。

例如,如果我给你4分,你可以

  1. 使用类似最小二乘法的方法近似一行
  2. 用最小二乘方法近似抛物线
  3. 通过这四点找到精确三次函数。
  4. 请务必选择适合您的方法!

答案 8 :(得分:0)

如果你知道如何将最小二乘问题表示为线性代数问题,那么使用Excel的矩阵函数来快速拟合是相当容易的。 (这取决于您认为Excel作为线性代数求解器的可靠性。)

答案 9 :(得分:-1)

lagrange polynomial在某种意义上是适合给定数据点集的“最简单”插值多项式。

有时会出现问题,因为数据点之间的差异很大。