web-dev-qa-db-fra.com

Ajustement des polynômes aux données

Existe-t-il un moyen, étant donné un ensemble de valeurs (x,f(x)), De trouver le polynôme d'un degré donné qui correspond le mieux aux données?

Je sais interpolation polynomiale , qui est pour trouver un polynôme de degré n étant donné n+1 Points de données, mais ici il y a un grand nombre de valeurs et nous voulons trouver un polynôme de faible degré (trouver le meilleur ajustement linéaire, le meilleur quadratique, le meilleur cubique, etc.). Cela pourrait être lié à moindres carrés ...

Plus généralement, j'aimerais connaître la réponse lorsque nous avons une fonction multivariée - des points comme (x,y,f(x,y)), Disons - et que nous voulons trouver le meilleur polynôme (p(x,y)) d'un degré donné dans les variables. (Plus précisément un polynôme, pas des splines ou des séries de Fourier.)

La théorie et le code/bibliothèques (de préférence en Python, mais tout langage est correct) seraient utiles.

48
ShreevatsaR

Merci pour les réponses de tout le monde. Voici une autre tentative pour les résumer. Pardon si je dis trop de choses "évidentes": je ne connaissais rien aux moindres carrés auparavant, donc tout était nouveau pour moi.

PAS d'interpolation polynomiale

interpolation polynomiale correspond à un polynôme de degré n étant donné n+1 Points de données, par ex. trouver un cube qui passe exactement par quatre points donnés. Comme dit dans la question, ce n'était pas ce que je voulais - j'avais beaucoup de points et je voulais un polynôme de petit degré (qui ne fera que environ en forme, sauf si nous avons eu de la chance) - mais comme certaines réponses insistaient pour en parler, je devrais les mentionner :) polynôme de Lagrange , matrice de Vandermonde , etc.

Qu'est-ce que les moindres carrés?

"Les moindres carrés" est une définition/critère/"métrique" particulier de "la qualité" d'un polynôme. (Il y en a d'autres, mais c'est plus simple.) Supposons que vous essayez d'ajuster un polynôme p (x, y) = a + bx + cy + dx2 + ey2 + fxy à certains points de données donnés (xje, yje, Zje) (où "Zje"était" f (xje, yje) "dans la question). Avec les moindres carrés, le problème est de trouver les" meilleurs "coefficients (a, b, c, d, e, f), de sorte que ce qui est minimisé (gardé" le moins ") soit la" somme ". de résidus carrés ", à savoir

S = ∑je (a + bxje + cyje + dxje2 + eyje2 + fxjeyje - Zje)2

Théorie

L'idée importante est que si vous regardez S en fonction de (a, b, c, d, e, f), alors S est minimisé à un point où son gradientest . Cela signifie que par exemple ∂S/∂f = 0, c'est-à-dire que

je2 (a +… + fxjeyje - Zje)Xjeyje = 0

et des équations similaires pour a, b, c, d, e. Notez que ce ne sont que des équations linéaires dans un… f. Nous pouvons donc les résoudre avec élimination gaussienne ou n'importe laquelle de les méthodes habituelles .

Ceci est encore appelé "moindres carrés linéaires", car bien que la fonction que nous voulions soit un polynôme quadratique, elle est toujours linéaire dans les paramètres (a, b, c, d, e, f) . Notez que la même chose fonctionne quand nous voulons que p (x, y) soit n'importe quelle "combinaison linéaire" de arbitraire fonctions fj, au lieu d'un simple polynôme (= "combinaison linéaire de monômes").

Code

Pour le cas univarié (quand il n'y a que la variable x - le fj sont des monômes xj), il y a 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

Pour le cas multivarié, ou les moindres carrés linéaires en général, il y a SciPy. Comme expliqué dans sa documentation , il prend une matrice A des valeurs fj(xje). (La théorie est qu'elle trouve le Moore-Penrose pseudoinverse of A.) Avec notre exemple ci-dessus impliquant (xje, yje, Zje), l'ajustement d'un polynôme signifie que le fj sont les monômes x()y(). Ce qui suit trouve le meilleur quadratique (ou le meilleur polynôme de tout autre degré, si vous modifiez la ligne "degré = 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

impressions

 + (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

il a donc découvert que le polynôme est x2+ 2xy + y2+0.01. [Le dernier terme est parfois -0,01 et parfois 0, ce qui est à prévoir en raison du bruit aléatoire que nous avons ajouté.]

Les alternatives à Python + Numpy/Scipy sont R et les systèmes d'algèbre informatique: Sage , Mathematica, Matlab, Maple. Même Excel pourrait le faire. Recettes numériques discute des méthodes pour l'implémenter nous-mêmes (en C, Fortran).

Préoccupations

  • Il est fortement influencé par la façon dont les points sont choisis . Quand j'avais x=y=range(20) au lieu des points aléatoires, cela produisait toujours 1,33x2+ 1.33xy + 1.33y2, ce qui était déroutant ... jusqu'à ce que je réalise que parce que j'avais toujours x[i]=y[i], les polynômes étaient les mêmes: x2+ 2xy + y2 = 4x2 = (4/3) (x2+ xy + y2). La morale est donc qu'il est important de choisir soigneusement les points pour obtenir le "bon" polynôme. (Si vous pouvez choisir, vous devez choisir nœuds Chebyshev pour l'interpolation polynomiale; vous ne savez pas si cela est également vrai pour les moindres carrés.)
  • Sur-ajustement : les polynômes de degré supérieur peuvent toujours mieux ajuster les données. Si vous changez le degree en 3 ou 4 ou 5, il reconnaît toujours le même polynôme quadratique (les coefficients sont 0 pour les termes de degré supérieur) mais pour les degrés plus grands, il commence à ajuster les polynômes de degré supérieur. Mais même avec le degré 6, prendre n plus grand (plus de points de données au lieu de 20, disons 200) correspond toujours au polynôme quadratique. La morale est donc d'éviter le surapprentissage, pour lequel il pourrait être utile de prendre autant de points de données que possible.
  • Il pourrait y avoir des problèmes de stabilité numérique Je ne comprends pas complètement.
  • Si vous n'avez pas besoin d'un polynôme, vous pouvez obtenir de meilleurs ajustements avec d'autres types de fonctions, par ex. splines (polynômes par morceaux).
57
ShreevatsaR

Oui, la façon dont cela se fait généralement est d'utiliser les moindres carrés. Il existe d'autres façons de spécifier dans quelle mesure un polynôme s'adapte, mais la théorie est la plus simple pour les moindres carrés. La théorie générale est appelée régression linéaire.

Votre meilleur pari est probablement de commencer par Recettes numériques .

R est gratuit et fera tout ce que vous voulez et plus, mais il a une grande courbe d'apprentissage.

Si vous avez accès à Mathematica, vous pouvez utiliser la fonction Ajuster pour ajuster les moindres carrés. J'imagine que Matlab et son homologue open source Octave ont une fonction similaire.

7
John D. Cook

Pour (x, f(x)) cas:

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)
5
jfs

Gardez à l'esprit qu'un polynôme de degré supérieur correspond TOUJOURS mieux aux données. Les polynômes de degré supérieur conduisent généralement à des fonctions hautement improbables (voir Rasoir d'Occam ), cependant (sur-ajustement). Vous voulez trouver un équilibre entre la simplicité (degré de polynôme) et l'ajustement (par exemple, l'erreur du moindre carré). Quantitativement, il existe des tests pour cela, le Akaike Information Criterion ou le Bayesian Information Criterion . Ces tests donnent un score sur le modèle à privilégier.

4
Fredriku73

Si vous voulez ajuster le ((xi, f (xi)) à un polynôme de degré n alors vous mettriez en place un problème de moindres carrés linéaires avec les données (1, xi, xi, xi ^ 2, ..., xi ^ n, f(xi)). Cela renverra un ensemble de coefficients (( c0, c1, ..., cn) de sorte que le polynôme le mieux adapté soit * y = c0 + c1 * x + c2 * x ^ 2 + ... + cn * x ^ n. *

Vous pouvez généraliser ces deux variables dépendantes en incluant des puissances de y et des combinaisons de x et y dans le problème.

2
David Norman

au collège, nous avions ce livre que je trouve toujours extrêmement utile: Conte, de Boor; analyse numérique élémentaire; Mc Grow Hill. Le paragraphe pertinent est 6.2: Ajustement des données.
L'exemple de code est fourni en FORTRAN, et les listes ne sont pas très lisibles non plus, mais les explications sont détaillées et claires en même temps. vous finissez par comprendre ce que vous faites, pas seulement par le faire (comme c'est mon expérience des recettes numériques).
Je commence habituellement par des recettes numériques mais pour des choses comme ça, je dois rapidement attraper Conte-de Boor.

peut-être mieux de poster du code ... c'est un peu dépouillé, mais les parties les plus pertinentes sont là. ça dépend de numpy, évidemment!

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
2
mariotomo

Les polynômes de Lagrange (comme @j w publié) vous donnent un ajustement exact aux points que vous spécifiez, mais avec des polynômes de degré supérieur à 5 ou 6, vous pouvez rencontrer une instabilité numérique.

Les moindres carrés vous donnent le polynôme "le mieux ajusté" avec une erreur définie comme la somme des carrés des erreurs individuelles. (prenez la distance le long de l'axe des y entre les points que vous avez et la fonction qui en résulte, mettez-les au carré et résumez-les) La fonction MATLAB polyfit fait cela, et avec plusieurs arguments de retour, vous pouvez l'avoir s'occupe automatiquement des problèmes de mise à l'échelle/décalage (par exemple, si vous avez 100 points entre x = 312,1 et 312,3 et que vous voulez un polynôme de 6e degré, vous allez vouloir calculer u = (x-312,2) /0,1 de sorte que le Les valeurs u sont réparties entre -1 et + =).

[~ # ~] notez [~ # ~] que les résultats des ajustements aux moindres carrés sont fortement influencé par la distribution des valeurs de l'axe des x. Si les valeurs x sont également espacées, vous obtiendrez des erreurs plus importantes aux extrémités. Si vous avez un cas où vous pouvez choisir les valeurs x et que vous vous souciez de l'écart maximal par rapport à votre fonction connue et d'un polynôme interpolateur, alors l'utilisation de polynômes de Chebyshev vous donnera quelque chose qui est proche du polynôme minimax parfait (qui est très difficile à calculer). Ceci est discuté assez longuement dans Recettes numériques.

Edit: D'après ce que je comprends, tout cela fonctionne bien pour les fonctions d'une variable. Pour les fonctions multivariées, il sera probablement beaucoup plus difficile si le degré est supérieur à, disons, 2. J'ai trouvé un référence sur Google Books .

2
Jason S

Il est assez facile de faire un ajustement rapide en utilisant les fonctions de matrice d'Excel si vous savez représenter le problème des moindres carrés comme un problème d'algèbre linéaire. (Cela dépend de la fiabilité que vous pensez qu'Excel est un solveur d'algèbre linéaire.)

0
duffymo

Rappelez-vous, il y a une grande différence entre approximatif le polynôme et trouver un exact un.

Par exemple, si je vous donne 4 points, vous pourriez

  1. Approximer une ligne avec une méthode comme les moindres carrés
  2. Approximer une parabole avec une méthode comme les moindres carrés
  3. Trouvez une fonction cubique exacte à travers ces quatre points.

Assurez-vous de sélectionner la méthode qui vous convient!

0
stalepretzel