Использование удобных классов
Удобные классы, предоставляемые пакетом полиномов, это:
| Имя | Обеспечивает |
|---|---|
| Polynomial | Ряд степеней |
| Chebyshev | Ряд Чебышева |
| Legendre | Ряд Лежандра |
| Laguerre | Ряд Лагуэра |
| Hermite | Ряд Эрмита |
| HermiteE | Ряд ЭрмитаE |
Ряды в этом контексте представляют собой конечные суммы соответствующих полиномиальных базисных функций, умноженных на коэффициенты. Например, ряд степеней выглядит так

и имеет коэффициенты
. Ряд Чебышева с теми же коэффициентами выглядит так

и более общим образом

где в данном случае
являются функциями Чебышева степени
, но могли бы также являться базисными функциями любого из других классов. Соглашение для всех классов состоит в том, что коэффициент
соответствует базисной функции степени i.
Все классы имеют одинаковые методы, и, в частности, они реализуют числовые операторы Python +, -, *, //, %, divmod, **, == и !=. Два последних могут быть немного проблематичными из-за ошибок округления с плавающей запятой. Теперь мы представим быстрое демонстрацию различных операций, используя NumPy версии 1.7.0.
Основы
Сначала нам нужен класс полинома и экземпляр полинома для работы. Классы можно импортировать непосредственно из пакета полиномов или из модуля соответствующего типа. Здесь мы импортируем из пакета и используем традиционный класс Polynomial из-за его знакомости:
>>> from numpy.polynomial import Polynomial as P >>> p = P([1,2,3]) >>> p Polynomial([ 1., 2., 3.], [-1., 1.], [-1., 1.])
Обратите внимание, что в длинной версии вывода есть три части. Первая — коэффициенты, вторая — область определения, третья — интервал:
>>> p.coef array([ 1., 2., 3.]) >>> p.domain array([-1., 1.]) >>> p.window array([-1., 1.])
Вывод полинома дает более короткий вид без области определения и интервала:
>>> print p poly([ 1. 2. 3.])
Мы будем рассматривать область определения и интервал, когда дойдем до подгонки, пока же мы их игнорируем и пройдем основные алгебраические и арифметические операции.
Сложение и вычитание:
>>> p + p Polynomial([ 2., 4., 6.], [-1., 1.], [-1., 1.]) >>> p - p Polynomial([ 0.], [-1., 1.], [-1., 1.])
Умножение:
>>> p * p Polynomial([ 1., 4., 10., 12., 9.], [-1., 1.], [-1., 1.])
Степень:
>>> p**2 Polynomial([ 1., 4., 10., 12., 9.], [-1., 1.], [-1., 1.])
Деление:
Оператор целочисленного деления ‘//’ является оператором деления для классов полиномов; полиномы в этом отношении рассматриваются как целые числа. Для версий Python < 3.x оператор ‘/’ отображается на ‘//’, как и в Python, для более поздних версий оператор ‘/’ будет работать только для деления на скаляры. В какой-то момент он будет устаревшим:
>>> p // P([-1, 1]) Polynomial([ 5., 3.], [-1., 1.], [-1., 1.])
Остаток:
>>> p % P([-1, 1]) Polynomial([ 6.], [-1., 1.], [-1., 1.])
Divmod:
>>> quo, rem = divmod(p, P([-1, 1])) >>> quo Polynomial([ 5., 3.], [-1., 1.], [-1., 1.]) >>> rem Polynomial([ 6.], [-1., 1.], [-1., 1.])
Вычисление:
>>> x = np.arange(5)
>>> p(x)
array([ 1., 6., 17., 34., 57.])
>>> x = np.arange(6).reshape(3,2)
>>> p(x)
array([[ 1., 6.],
[ 17., 34.],
[ 57., 86.]])
Подстановка:
Подставьте полином для x и разложите результат. Здесь мы подставляем p в себя, что приводит к новому полиному степени 4 после разложения. Если полиномы рассматривать как функции, это композиция функций:
>>> p(p) Polynomial([ 6., 16., 36., 36., 27.], [-1., 1.], [-1., 1.])
Корни:
>>> p.roots() array([-0.33333333-0.47140452j, -0.33333333+0.47140452j])
Не всегда удобно явно использовать экземпляры Polynomial, поэтому кортежи, списки, массивы и скаляры автоматически преобразуются в арифметических операциях:
>>> p + [1, 2, 3] Polynomial([ 2., 4., 6.], [-1., 1.], [-1., 1.]) >>> [1, 2, 3] * p Polynomial([ 1., 4., 10., 12., 9.], [-1., 1.], [-1., 1.]) >>> p / 2 Polynomial([ 0.5, 1. , 1.5], [-1., 1.], [-1., 1.])
Полиномы, отличающиеся по области определения, интервалу или классу, не могут быть смешаны в арифметических операциях:
>>> from numpy.polynomial import Chebyshev as T >>> p + P([1], domain=[0,1]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 213, in __add__ TypeError: Domains differ >>> p + P([1], window=[0,1]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 215, in __add__ TypeError: Windows differ >>> p + T([1]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 211, in __add__ TypeError: Polynomial types differ
Но разные типы могут использоваться для подстановки. Фактически, именно так происходит преобразование классов Polynomial друг в друга для преобразования типов, области определения и интервала:
>>> p(T([0, 1])) Chebyshev([ 2.5, 2. , 1.5], [-1., 1.], [-1., 1.])
Что дает полином p в форме Чебышева. Это работает, потому что
и подстановка
для
не изменяет исходный полином. Однако все умножения и деления будут выполняться с использованием ряда Чебышева, следовательно, и тип результата.
Математический анализ
Экземпляры Polynomial могут быть интегрированы и дифференцированы:
>>> from numpy.polynomial import Polynomial as P >>> p = P([2, 6]) >>> p.integ() Polynomial([ 0., 2., 3.], [-1., 1.], [-1., 1.]) >>> p.integ(2) Polynomial([ 0., 0., 1., 1.], [-1., 1.], [-1., 1.])
Первый пример интегрирует p один раз, второй пример интегрирует его дважды. По умолчанию нижняя граница интегрирования и постоянная интегрирования равны 0, но оба можно указать:
>>> p.integ(lbnd=-1) Polynomial([-1., 2., 3.], [-1., 1.], [-1., 1.]) >>> p.integ(lbnd=-1, k=1) Polynomial([ 0., 2., 3.], [-1., 1.], [-1., 1.])
В первом случае нижняя граница интегрирования установлена в -1, а постоянная интегрирования — в 0. Во втором случае постоянная интегрирования также установлена в 1. Дифференцирование проще, так как единственный параметр — количество раз, которое полином дифференцируется:
>>> p = P([1, 2, 3]) >>> p.deriv(1) Polynomial([ 2., 6.], [-1., 1.], [-1., 1.]) >>> p.deriv(2) Polynomial([ 6.], [-1., 1.], [-1., 1.])
Другие конструкторы полиномов
Создание полиномов путем задания коэффициентов — это всего лишь один способ получения экземпляра полинома; их также можно создать, задав их корни, путем преобразования из других типов полиномов и с помощью наименьших квадратов. Подгонка обсуждается в отдельном разделе, другие методы продемонстрированы ниже:
>>> from numpy.polynomial import Polynomial as P >>> from numpy.polynomial import Chebyshev as T >>> p = P.fromroots([1, 2, 3]) >>> p Polynomial([ -6., 11., -6., 1.], [-1., 1.], [-1., 1.]) >>> p.convert(kind=T) Chebyshev([ -9. , 11.75, -3. , 0.25], [-1., 1.], [-1., 1.])
Метод преобразования также может преобразовывать область определения и интервал:
>>> p.convert(kind=T, domain=[0, 1]) Chebyshev([-2.4375 , 2.96875, -0.5625 , 0.03125], [ 0., 1.], [-1., 1.]) >>> p.convert(kind=P, domain=[0, 1]) Polynomial([-1.875, 2.875, -1.125, 0.125], [ 0., 1.], [-1., 1.])
В версиях NumPy >= 1.7.0 также доступны методы basis и cast класса. Метод преобразования работает как метод преобразования, а метод базиса возвращает базисный полином заданной степени:
>>> P.basis(3) Polynomial([ 0., 0., 0., 1.], [-1., 1.], [-1., 1.]) >>> T.cast(p) Chebyshev([ -9. , 11.75, -3. , 0.25], [-1., 1.], [-1., 1.])
Преобразования между типами могут быть полезны, но их не рекомендуется использовать в обычном случае. Потеря точности чисел при переходе от ряда Чебышева степени 50 к ряду полиномов той же степени может сделать результаты численного вычисления по существу случайными.
Подгонка
Подгонка — это причина, по которой атрибуты domain и window являются частью удобных классов. Чтобы проиллюстрировать проблему, ниже приведены графики значений полиномов Чебышева до степени 5.
>>> import matplotlib.pyplot as plt >>> from numpy.polynomial import Chebyshev as T >>> x = np.linspace(-1, 1, 100) >>> for i in range(6): ax = plt.plot(x, T.basis(i)(x), lw=2, label="$T_%d$"%i) ... >>> plt.legend(loc="upper left") <matplotlib.legend.Legend object at 0x3b3ee10> >>> plt.show()
(Исходный код, png, pdf)
В диапазоне -1 <= x <= 1 они являются хорошими, равнопеременными функциями, лежащими между +/- 1. Те же графики в диапазоне -2 <= x <= 2 выглядят совершенно иначе:
>>> import matplotlib.pyplot as plt >>> from numpy.polynomial import Chebyshev as T >>> x = np.linspace(-2, 2, 100) >>> for i in range(6): ax = plt.plot(x, T.basis(i)(x), lw=2, label="$T_%d$"%i) ... >>> plt.legend(loc="lower right") <matplotlib.legend.Legend object at 0x3b3ee10> >>> plt.show()
(Исходный код, png, pdf)
Как видно, «хорошие» части уменьшились до незначительности. При использовании полиномов Чебышева для подгонки мы хотим использовать область, где x находится между -1 и 1, и именно это задает window. Однако маловероятно, что данные, подлежащие подгонке, имеют все свои точки данных в этом интервале, поэтому мы используем domain для задания интервала, в котором находятся точки данных. При выполнении подгонки область определения сначала отображается на интервал с помощью линейного преобразования, и выполняется обычная подгонка наименьших квадратов с использованием отображенных точек данных. Интервал и область определения подгонки являются частью возвращаемого ряда и автоматически используются при вычислении значений, производных и т. д. Если они не указаны в вызове, процедура подгонки будет использовать интервал по умолчанию и наименьшую область определения, содержащую все точки данных. Это иллюстрируется ниже для подгонки к шумной синусоиде.
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from numpy.polynomial import Chebyshev as T >>> np.random.seed(11) >>> x = np.linspace(0, 2*np.pi, 20) >>> y = np.sin(x) + np.random.normal(scale=.1, size=x.shape) >>> p = T.fit(x, y, 5) >>> plt.plot(x, y, 'o') [<matplotlib.lines.Line2D object at 0x2136c10>] >>> xx, yy = p.linspace() >>> plt.plot(xx, yy, lw=2) [<matplotlib.lines.Line2D object at 0x1cf2890>] >>> p.domain array([ 0. , 6.28318531]) >>> p.window array([-1., 1.]) >>> plt.show()
(Исходный код, png, pdf)
© 2008–2017 NumPy Developers
Licensed under the NumPy License.
https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.polynomials.classes.html