Spec-Zone.ru › NumPy 1.13

Использование удобных классов

Удобные классы, предоставляемые пакетом полиномов, это:

Имя Обеспечивает
Polynomial Ряд степеней
Chebyshev Ряд Чебышева
Legendre Ряд Лежандра
Laguerre Ряд Лагуэра
Hermite Ряд Эрмита
HermiteE Ряд ЭрмитаE

Ряды в этом контексте представляют собой конечные суммы соответствующих полиномиальных базисных функций, умноженных на коэффициенты. Например, ряд степеней выглядит так

p(x) = 1 + 2x + 3x^2

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

p(x) = 1 T_0(x) + 2 T_1(x) + 3 T_2(x)

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

p(x) = \sum_{i=0}^n c_i T_i(x)

где в данном случае T_n являются функциями Чебышева степени n, но могли бы также являться базисными функциями любого из других классов. Соглашение для всех классов состоит в том, что коэффициент c[i] соответствует базисной функции степени 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 в форме Чебышева. Это работает, потому что T_1(x) = x и подстановка x для x не изменяет исходный полином. Однако все умножения и деления будут выполняться с использованием ряда Чебышева, следовательно, и тип результата.

Математический анализ

Экземпляры 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)

../_images/routines-polynomials-classes-1.png

В диапазоне -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)

../_images/routines-polynomials-classes-2.png

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

../_images/routines-polynomials-classes-3.png

© 2008–2017 NumPy Developers
Licensed under the NumPy License.
https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.polynomials.classes.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API