Dopasowanie wielomianów do danych

Czy istnieje sposób, biorąc pod uwagę zbiór wartości (x,f(x)), aby znaleźć wielomian danego stopnia, który najlepiej pasuje do danych?

Znaminterpolację wielomianową , która służy do znalezienia wielomianu stopnia n podanego n+1 punktów danych, ale tutaj jest duża liczba wartości i chcemy znaleźć wielomian niskiego stopnia (znaleźć najlepsze dopasowanie liniowe, najlepsze kwadratowe, najlepsze sześcienne itp.). Może być związane z najmniejszymi kwadratami ...

Bardziej ogólnie, chciałbym wiedzieć odpowiadamy, gdy mamy funkcję wielowymiarową-punkty takie jak (x,y,f(x,y)), powiedzmy -- i chcemy znaleźć najlepszy wielomian (p(x,y)) danego stopnia w zmiennych. (Konkretnie wielomian, a nie splajny czy Szereg Fouriera.)

Zarówno teoria, jak i kod/biblioteki (najlepiej w Pythonie, ale każdy język jest w porządku) byłyby użyteczne.

Author: ShreevatsaR, 2008-12-19

10 answers

Dzięki za odpowiedzi. Oto kolejna próba ich podsumowania. Wybacz, jeśli mówię zbyt wiele "oczywistych" rzeczy: wcześniej nic nie wiedziałem o najmniejszych kwadratach, więc wszystko było dla mnie nowe.

Nie interpolacja wielomianowa

Interpolacja wielomianowa {[15] } jest dopasowaniem wielomianu stopnia n podanego n+1 punktów danych, np. znalezienie sześciennego, który przechodzi dokładnie przez cztery podane punkty. Jak powiedzialem w pytaniu, to nie chcialem-mialem duzo punktów i chciał wielomianu małego stopnia (który będzie pasował tylko w przybliżeniu, chyba, że mamy szczęście) - ale skoro niektóre odpowiedzi nalegały na mówienie o tym, powinienem o nich wspomnieć :) wielomian Lagrange 'a, macierz Vandermonde' a , itd.

Co to jest najmniejsze kwadraty?

"najmniejsze kwadraty" to szczególna definicja / kryterium / metryka "jak dobrze" wielomian pasuje. (Są inne, ale to jest najprostsze.) Powiedz, że próbujesz dopasować wielomian p (x, y) = a + bx + cy + DX2 + ey2 + fxy w niektórych punktach danych (xi,yi,Zi) (gdzie "Zi" było "f(xi,yi)" w pytaniu). W przypadku najmniejszych kwadratów problem polega na znalezieniu "najlepszych" współczynników (a,b,c,d,e,f), takich, że to, co jest zminimalizowane (utrzymywane "najmniej"), jest "sumą kwadratowych pozostałości", a mianowicie

S = ∑i (a + bxi + cy i + dx i2 + ey i2 + fxi y i - Z i)2

Teoria

Ważną ideą jest to, że jeśli spojrzeć na s jako funkcję (A, b, c, d, e, f), to S jest zminimalizowane w punkcie, w którym jej gradient is 0 . Oznacza to, że na przykład ∂S / ∂f = 0, tzn. że

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

I podobne równania dla a, b, c, d, e. Zauważ, że są to tylko równania liniowe w...f. więc możemy je rozwiązać eliminacją Gaussa lub którąkolwiek z zwykłymi metodami.

Jest to nadal nazywane "najmniejszymi kwadratami liniowymi", ponieważ chociaż funkcja, którą chcieliśmy, była wielomianem kwadratowym, to nadal jest liniowa w parametrach (a,b, c, d, e, f). Zauważ, że to samo działa, gdy chcemy, aby P (x,y) była dowolną "kombinacją liniową" dowolnych funkcji f j , zamiast tylko wielomian (="liniowa kombinacja monomianów").

Kod

Dla przypadku jednostajnego (gdy istnieje tylko zmienna x-Fj są jednomianami x j ), istnieje 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

Dla przypadku wielowymiarowego, lub liniowego najmniejszego kwadratu w ogóle, istnieje SciPy. jak wyjaśniono w jego dokumentacji , przyjmuje macierz A wartości f j(xi ). (Teoria jest taka, że znajduje Moore-Penrose pseudoinverse z A.) z naszym powyższym przykładem obejmującym (x i ,y i ,Z i ), dopasowanie wielomianu oznacza, że F j są jednomianami x()y(). Poniżej znajduje się najlepszy kwadratowy (lub najlepszy wielomian dowolnego innego stopnia, jeśli zmienisz linię "Stopień = 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

Druki

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

Więc okazało się, że wielomian jest x2+2xy + y2+0.01. [Ostatni termin to czasami -0.01, a czasami 0, czego można się spodziewać ze względu na przypadkowy szum, który dodaliśmy.]

Alternatywami dla Pythona + Numpy / Scipy są R i systemy algebry komputerowej: Sage , Mathematica, Matlab, Maple. Nawet Excel może to zrobić. Numerical Recipes omawia metody jej implementacji (w C, Fortran).

Obawy

    Na to duży wpływ ma sposób wybierania punktów. Kiedy miałem x=y=range(20) zamiast losowych punktów zawsze dawało 1,33 x2+1.33 xy+1,33 y2, co było zastanawiające... dopóki nie uświadomiłem sobie, że ponieważ zawsze miałem x[i]=y[i], wielomiany były takie same: x2+2xy + y2 = 4x2 = (4/3)(x2+xy + y2). Morał polega więc na tym, że ważne jest, aby starannie dobierać punkty, aby uzyskać "właściwy" wielomian. (Jeśli możesz wybrać, powinieneś wybrać węzły Czebyszewa dla interpolacji wielomianowej; nie jestem pewien jeśli to samo dotyczy również najmniejszych kwadratów.)
  • Overfitting : wielomiany wyższego stopnia zawsze lepiej pasują do danych. Jeśli zmienisz degree na 3, 4 lub 5, nadal rozpoznaje ten sam wielomian kwadratowy (współczynniki są równe 0 dla terminów wyższych stopni), ale dla większych stopni zaczyna dopasowywać wielomiany wyższych stopni. Ale nawet w stopniu 6, biorąc większe n (więcej punktów danych zamiast 20, powiedzmy 200) nadal pasuje do wielomianu kwadratowego. Tak więc morał polega na unikaniu przesady, co może pomóc w zdobyciu jak największej liczby punktów danych.
  • mogą być problemy stabilności numerycznej nie do końca rozumiem.
  • jeśli nie potrzebujesz wielomianu, możesz uzyskać lepsze dopasowanie do innych rodzajów funkcji, np. splines (wielomiany piecewise).
 54
Author: ShreevatsaR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-31 23:11:00

Tak, zazwyczaj odbywa się to za pomocą najmniejszych kwadratów. Istnieją inne sposoby określania, jak dobrze pasuje wielomian, ale teoria jest najprostsza dla najmniejszych kwadratów. Ogólna teoria nazywa się regresją liniową.

Najlepiej zacząć od numerycznych przepisów .

R jest darmowy i zrobi wszystko, co chcesz i więcej, ale ma dużą krzywą uczenia się.

Jeśli masz dostęp do Mathematica, możesz użyć funkcji Fit, aby najmniej kwadratów pasuje. Domyślam się, że Matlab i jego open source odpowiednik Octave mają podobną funkcję.

 7
Author: John D. Cook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-06 21:27:43

For (x, f(x)) case:

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
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-19 21:33:23

Należy pamiętać, że wielomian wyższego stopnia zawsze lepiej pasuje do danych. Wielomiany wyższego stopnia zazwyczaj prowadzą do wysoce nieprawdopodobnych funkcji (Zobacz brzytwa Occama), choć (overfitting). Chcesz znaleźć równowagę między prostotą (stopień wielomianu) a dopasowaniem (np. błąd najmniejszego kwadratu). Ilościowe, istnieją testy na to, Akaike Information Criterion lub Bayessian Information Criterion . Te testy dają wynik, który model ma być lepiej.

 4
Author: Fredriku73,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-20 09:52:55

Jeśli chcesz dopasować (xi, f (xi)) do wielomianu stopnia n wtedy ustawisz liniowy problem najmniejszych kwadratów z danymi (1, xi, xi, xi^2,..., xi^n, f (xi)). zwróci to zbiór współczynników (c0, c1, ..., cn) tak, że najlepiej dopasowanym wielomianem jest *y = C0 + c1 * x + c2 * x^2+... + cn * x^n. *

Można uogólnić te dwie więcej niż jedną zmienną zależną przez uwzględnienie potęg y i kombinacji x i y w problemie.

 2
Author: David Norman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-19 21:35:16

Wielomiany Lagrange ' a (jak napisał @j w) dają dokładne dopasowanie do punktów, które określisz, ale z wielomianami stopnia większego niż powiedzmy 5 lub 6, możesz napotkać niestabilność numeryczną.

Najmniejsze kwadraty daje wielomian" najlepiej dopasowany " z błędem zdefiniowanym jako suma kwadratów poszczególnych błędów. (weź odległość wzdłuż osi y między punktami, które masz, a funkcją, która daje wynik, kwadrat je i zsumuj je) funkcja MATLAB polyfit robi to i z wieloma jeśli masz 100 punktów między x = 312.1 i 312.3, i chcesz wielomian 6 stopnia, będziesz chciał obliczyć u = (x-312.2) / 0.1, więc wartości u są rozłożone między -1 i+=).

Zauważ , że wyniki pasowań najmniejszych kwadratów są silnie pod wpływem rozkładu wartości osi X. Jeśli wartości x są równomiernie rozmieszczone, wtedy pojawią się większe błędy w koniec. Jeśli masz przypadek, w którym możesz wybrać wartości x i zależy ci na maksymalnym odchyleniu od znanej funkcji i wielomianu interpolującego, to użycie wielomianów Czebyszewa da ci coś, co jest bliskie idealnemu wielomianowi minimax (który jest bardzo trudny do obliczenia). Jest to omawiane w pewnej mierze w numerycznych recepturach.

Edit: z tego co wiem, to wszystko działa dobrze dla funkcji jednej zmiennej. Dla wielowymiarowych funkcje może to być znacznie trudniejsze, jeśli stopień jest większy niż, powiedzmy, 2. Znalazłem odnośnik w Google Books.

 2
Author: Jason S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-19 22:38:26

Na studiach mieliśmy tę książkę, która nadal uważam za niezwykle przydatna: Conte, de Boor; elementarna Analiza numeryczna; Mc Grow Hill. Odpowiedni punkt to 6.2: dopasowanie danych.
przykładowy kod pojawia się w FORTRAN, a listy również nie są zbyt czytelne, ale wyjaśnienia są głębokie i jasne jednocześnie. w końcu rozumiesz, co robisz, a nie tylko to robisz (tak jak moje doświadczenie z numerycznymi przepisami).
Zazwyczaj zaczynam od numerycznych przepisów, ale dla takich rzeczy szybko trzeba złapać Conte-de Boor.

Może lepiej wrzucić jakiś kod... jest trochę rozebrany, ale najważniejsze części są tam. oczywiście opiera się na 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
 2
Author: mariotomo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-28 12:39:42

Pamiętaj, jest duża różnica między przybliżeniem wielomianu a znalezieniem dokładnego .

Na przykład, jeśli dam ci 4 punkty, możesz

  1. przybliżenie linii metodą jak najmniejszych kwadratów
  2. przybliżenie paraboli metodą jak najmniejszych kwadratów
  3. Znajdź dokładną funkcję sześcienną przez te cztery punkty.

Pamiętaj, aby wybrać metodę, która jest odpowiednia dla Ciebie!

 0
Author: stalepretzel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-21 16:34:25

Łatwo jest przestraszyć szybkie dopasowanie za pomocą funkcji macierzy Excela, jeśli wiesz, jak przedstawić problem najmniejszych kwadratów jako problem algebry liniowej. (To zależy od tego, jak niezawodny jest Excel jako rozwiązywanie algebry liniowej.)

 0
Author: duffymo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-28 15:57:24

Wielomian lagrange ' a jest w pewnym sensie "najprostszym" wielomianem interpolacyjnym, który pasuje do danego zbioru punktów danych.

Jest to czasami problematyczne, ponieważ może się bardzo różnić między punktami danych.

 -1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-19 21:40:13