Подгонка полиномов к данным - PullRequest
48 голосов
/ 19 декабря 2008

Есть ли способ, учитывая набор значений (x,f(x)), найти полином заданной степени, который наилучшим образом соответствует данным?

Я знаю полиномиальная интерполяция , которая предназначена для нахождения полинома степени n с учетом n+1 точек данных, но здесь есть большое количество значений, и мы хотим найти низкую степень полином (найти наилучшее линейное соответствие, лучшее квадратичное, лучшее кубическое и т. д.). Это может быть связано с наименьших квадратов ...

В более общем смысле, я хотел бы знать ответ, когда у нас есть многовариантная функция - скажем, точки (x,y,f(x,y)), и мы хотим найти наилучший полином (p(x,y)) заданной степени в переменных. (В частности, полином, а не сплайны или ряды Фурье.)

Будет полезна и теория, и код / ​​библиотеки (желательно на Python, но с любым языком все в порядке).

Ответы [ 10 ]

56 голосов
/ 20 декабря 2008

Спасибо за все ответы. Вот еще одна попытка их обобщения. Простите, если я скажу слишком много «очевидных» вещей: раньше я ничего не знал о наименьших квадратах, так что все было для меня новым.

НЕ полиномиальная интерполяция

Полиномиальная интерполяция соответствует полиному степени 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), чтобы минимизировать (сохранить «наименьшее») «сумму квадратов невязок», а именно: 1035 *

S = & sum; i (a + bx i + cy i + dx i 2 + эй я 2 + фх я у я - Z я ) 2

Теория

Важная идея заключается в том, что если вы посмотрите на S как на функцию (a, b, c, d, e, f), то S будет минимизировано в точке, в которой его градиент равен 0 . Это означает, что, например, 'part; S /'; part = f = 0, то есть

& sum; i 2 (a + & hellip; + fx i y i - Z i ) x i у я = 0

и аналогичные уравнения для a, b, c, d, e. Обратите внимание, что это просто линейные уравнения в a & hellip; 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. Как объяснено в документации , она принимает матрицу A значений f j ( x i ). (Теория состоит в том, что он находит псевдообратную Мура-Пенроуза of A.) В нашем приведенном выше примере (x i , y i , Z i ), подгонка полинома означает, что f j являются мономами x () y () . Следующее находит лучший квадратик (или лучший многочлен любой другой степени, если вы измените строку «степень = 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 может сделать это. Числовые рецепты обсуждает методы, чтобы реализовать его самостоятельно (на 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 * * + одна тысяча сто семьдесят одна х + у * 2 * одна тысяча сто семьдесят два * +1173 *). Поэтому мораль заключается в том, что важно тщательно выбирать точки, чтобы получить «правильный» многочлен. (Если вы можете выбрать, вы должны выбрать чебышевские узлы для полиномиальной интерполяции; не уверены, что то же самое верно и для наименьших квадратов.)
  • Переоснащение : полиномы более высокой степени всегда могут лучше соответствовать данным. Если вы измените degree на 3, 4 или 5, он по-прежнему в основном распознает тот же квадратичный полином (коэффициенты равны 0 для членов более высокой степени), но для больших степеней он начинает подгонять полиномы более высокой степени. Но даже с 6-й степенью взятие большего n (больше точек данных вместо 20, скажем, 200) по-прежнему соответствует квадратичному полиному. Таким образом, мораль состоит в том, чтобы избежать переобучения, для чего это может помочь собрать как можно больше данных.
  • Могут быть проблемы числовой стабильности Я не до конца понимаю.
  • Если вам не нужен многочлен, вы можете получить лучшее согласование с другими видами функций, например, сплайны (кусочно-полиномы).
7 голосов
/ 20 декабря 2008

Да, обычно это делается с помощью метода наименьших квадратов. Есть и другие способы указать, насколько хорошо подходит многочлен, но теория простейшая для наименьших квадратов. Общая теория называется линейной регрессией.

Лучше всего начинать с Числовые рецепты .

R бесплатен и будет делать все, что вы хотите, и даже больше, но у него большая кривая обучения.

Если у вас есть доступ к Mathematica, вы можете использовать функцию Fit для подгонки по методу наименьших квадратов. Я полагаю, что Matlab и его коллега с открытым исходным кодом Octave имеют похожую функцию.

5 голосов
/ 20 декабря 2008

Для случая (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)
4 голосов
/ 20 декабря 2008

Имейте в виду, что полином более высокой степени ВСЕГДА лучше соответствует данным. Полиномы более высокой степени обычно приводят к крайне невероятным функциям (см. Razor Оккама ), хотя (переоснащение). Вы хотите найти баланс между простотой (степень полинома) и соответствием (например, ошибка наименьших квадратов). Количественно существуют тесты для этого, Информационный критерий Акаике или Байесовский информационный критерий . Эти тесты дают оценку, какая модель предпочтительнее.

2 голосов
/ 28 июля 2009

в колледже у нас была эта книга, которую я до сих пор считаю чрезвычайно полезной: Конте, де Бур; элементарный численный анализ; Mc Grow Hill. Соответствующий пункт 6.2: Подгонка данных.
Пример кода поставляется на Фортране, и листинги тоже не очень читабельны, но объяснения в то же время глубоки и понятны. в конечном итоге вы понимаете, что вы делаете, а не просто делаете это (как мой опыт работы с числовыми рецептами).
Я обычно начинаю с Числовых Рецептов, но для таких вещей мне нужно быстро схватить 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
2 голосов
/ 20 декабря 2008

Лагранжевы полиномы (как написано @j w) дают вам точное соответствие в указанных точках, но с полиномами степени, превышающими, скажем, 5 или 6, вы можете столкнуться с численной нестабильностью.

Наименьшие квадраты дают вам полином "наилучшего соответствия" с ошибкой, определяемой как сумма квадратов отдельных ошибок. (возьмите расстояние вдоль оси Y между имеющимися точками и полученной функцией, возведите их в квадрат и суммируйте). Функция MATLAB polyfit делает это, и с несколькими возвращаемыми аргументами вы можете автоматически позаботиться о ней. вопросов масштабирования / смещения (например, если у вас есть 100 точек между x = 312.1 и 312.3, и вы хотите получить полином 6-й степени, вам нужно вычислить u = (x-312.2) /0.1, чтобы значения u распределяются между -1 и + =).

ПРИМЕЧАНИЕ что результаты подгонки по методу наименьших квадратов сильно зависят от распределения значений по оси x. Если x-значения расположены одинаково, то на концах вы получите большие ошибки. Если у вас есть случай, когда вы можете выбрать значения x и вам небезразлично максимальное отклонение от вашей известной функции и интерполирующего полинома, то использование полиномов Чебышева даст вам кое-что это близко к идеальному минимаксному многочлену (который очень трудно вычислить). Это обсуждено довольно подробно в Числовых Рецептах.

Редактировать: Из того, что я понял, все это хорошо работает для функций одной переменной. Для многомерных функций, вероятно, будет гораздо сложнее, если степень больше, чем, скажем, 2. Я нашел ссылку в Google Книгах .

2 голосов
/ 20 декабря 2008

Если вы хотите подогнать (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 .

0 голосов
/ 28 декабря 2008

Быстрое подгонка довольно просто с помощью матричных функций Excel, если вы знаете, как представить задачу наименьших квадратов как задачу линейной алгебры. (Это зависит от того, насколько надежным вы считаете Excel в качестве решателя линейной алгебры.)

0 голосов
/ 21 декабря 2008

Помните, что есть большая разница между аппроксимацией полинома и нахождением точного единицы.

Например, если я дам вам 4 балла, вы могли бы

  1. Приблизить линию методом наименьших квадратов
  2. Приближение параболы методом, подобным методу наименьших квадратов
  3. Найдите точную кубическую функцию через эти четыре точки.

Обязательно выберите метод, который подходит именно вам!

0 голосов
/ 20 декабря 2008

полином Лагранжа в некотором смысле является "самым простым" интерполяционным полиномом, который соответствует данному набору точек данных.

Иногда это проблематично, поскольку он может сильно различаться между точками данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...