BarycentricInterpolator#
- класс scipy.interpolate.BarycentricInterpolator(xi, yi=None, ось=0, *, wi=None, rng=None, random_state=None)[источник]#
Барицентрический интерполятор (Лагранжа с улучшенной стабильностью) (гладкость C∞).
Строит полином, проходящий через заданный набор точек. Позволяет вычислять полином и все его производные, эффективно изменять интерполируемые y-значения и обновлять, добавляя больше x- и y-значений. Для численной устойчивости используется барицентрическое представление вместо непосредственного вычисления коэффициентов полинома.
- Параметры:
- xiarray_like, shape (npoints, )
1-D массив x-координат точек, через которые должен проходить полином
- yiarray_like, форма (…, npoints, …), необязательно
N-мерный массив y-координат точек, через которые должен проходить полином. Если None, значения y будут предоставлены позже через set_y метода. Длина yi вдоль оси интерполяции должна быть равна длине xi. Используйте
axisпараметр для выбора правильной оси.- осьint, необязательный
Ось в массиве yi, соответствующая значениям координаты x. По умолчанию
axis=0.- wiarray_like, необязательный
Барицентрические веса для выбранных точек интерполяции xi. Если отсутствует или None, веса будут вычислены из xi (по умолчанию). Это позволяет повторно использовать веса wi если несколько интерполянтов вычисляются с использованием одних и тех же узлов xi, без перевычисления. Это также позволяет явно вычислять веса для некоторых вариантов xi (см. примечания).
- rng{None, int,
numpy.random.Generator, опционально Если rng передается по ключевому слову, типы, отличные от
numpy.random.Generatorпередаются вnumpy.random.default_rngдля создания экземпляраGenerator. Если rng уже являетсяGeneratorэкземпляр, то предоставленный экземпляр используется. Укажите rng для воспроизводимой интерполяции.Если этот аргумент random_state передается по ключевому слову, устаревшее поведение для аргумента random_state применяется:
Если random_state равно None (или
numpy.random),numpy.random.RandomStateиспользуется синглтон.Если random_state является int, новый
RandomStateиспользуется экземпляр, инициализированный с random_state.Если random_state уже является
GeneratorилиRandomStateэкземпляр, тогда этот экземпляр используется.
Изменено в версии 1.15.0: В рамках SPEC-007 переход от использования
numpy.random.RandomStatetonumpy.random.Generatorэто ключевое слово было изменено с random_state to rng. В течение переходного периода оба ключевых слова будут продолжать работать (укажите только одно из них). После переходного периода использование random_state ключевое слово будет выдавать предупреждения. Поведение random_state и rng ключевые слова описаны выше.
- Атрибуты:
- dtype
Методы
__call__(x)Вычислить интерполяционный полином в точках x
add_xi(xi[, yi])Добавьте больше значений x в набор для интерполяции
derivative(x[, der])Вычислить одну производную полинома в точке x.
derivatives(x[, der])Вычислить несколько производных полинома в точке x
set_yi(yi[, axis])Обновить значения y для интерполяции
Примечания
Этот метод является вариантом интерполяции полиномами Лагранжа [1] на основе [2]. Вместо использования формулы Лагранжа или Ньютона, полином представлен барицентрической формулой
\[p(x) = \frac{\sum_{i=1}^m\ w_i y_i / (x - x_i)}{\sum_{i=1}^m w_i / (x - x_i)},\]где \(w_i\) являются барицентрическими весами, вычисленными по общей формуле
\[w_i = \left( \prod_{k \neq i} x_i - x_k \right)^{-1}.\]Это та же барицентрическая форма, используемая
AAAиFloaterHormannInterpolator. Однако, в отличие от этого, веса \(w_i\) определены так, что \(p(x)\) является полиномом, а не рациональной функцией.Барицентрическое представление позволяет избежать многих проблем, связанных с интерполяцией полиномов, вызванных арифметикой с плавающей запятой. Однако оно не позволяет избежать проблем, присущих интерполяции полиномов. А именно, если координаты x распределены равномерно, то веса могут быть вычислены явно с использованием формулы из [2]
\[w_i = (-1)^i {n \choose i},\]где \(n\) это количество x-координат. Как отмечено в [2], это означает, что для больших \(n\) веса изменяются экспоненциально большими коэффициентами, что приводит к явлению Рунге.
Чтобы избежать этой плохой обусловленности, x-координаты должны быть сгруппированы на концах интервала. Отличный выбор точек на интервале \([a,b]\) являются точками Чебышёва второго рода
\[x_i = \frac{a + b}{2} + \frac{a - b}{2}\cos(i\pi/n).\]в этом случае веса могут быть вычислены явно как
\[\begin{split}w_i = \begin{cases} (-1)^i/2 & i = 0,n \\ (-1)^i & \text{otherwise} \end{cases}.\end{split}\]См. [2] для дополнительной информации. Обратите внимание, что для больших \(n\), вычисление весов явно (см. примеры) будет быстрее, чем общая формула.
Ссылки
[2] (1,2,3,4)Жан-Поль Берру и Ллойд Н. Трефетен, “Барицентрическая интерполяция Лагранжа”, SIAM Review 2004 46:3, 501-517 DOI:10.1137/S0036144502417715
Примеры
Для создания квинтического барицентрического интерполянта, аппроксимирующего функцию \(\sin x\), и его первые четыре производные, используя шесть случайно расположенных узлов в \((0, \pi/2)\):
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from scipy.interpolate import BarycentricInterpolator >>> rng = np.random.default_rng() >>> xi = rng.random(6) * np.pi/2 >>> f, f_d1, f_d2, f_d3, f_d4 = np.sin, np.cos, lambda x: -np.sin(x), lambda x: -np.cos(x), np.sin >>> P = BarycentricInterpolator(xi, f(xi), random_state=rng) >>> fig, axs = plt.subplots(5, 1, sharex=True, layout='constrained', figsize=(7,10)) >>> x = np.linspace(0, np.pi, 100) >>> axs[0].plot(x, P(x), 'r:', x, f(x), 'k--', xi, f(xi), 'xk') >>> axs[1].plot(x, P.derivative(x), 'r:', x, f_d1(x), 'k--', xi, f_d1(xi), 'xk') >>> axs[2].plot(x, P.derivative(x, 2), 'r:', x, f_d2(x), 'k--', xi, f_d2(xi), 'xk') >>> axs[3].plot(x, P.derivative(x, 3), 'r:', x, f_d3(x), 'k--', xi, f_d3(xi), 'xk') >>> axs[4].plot(x, P.derivative(x, 4), 'r:', x, f_d4(x), 'k--', xi, f_d4(xi), 'xk') >>> axs[0].set_xlim(0, np.pi) >>> axs[4].set_xlabel(r"$x$") >>> axs[4].set_xticks([i * np.pi / 4 for i in range(5)], ... ["0", r"$\frac{\pi}{4}$", r"$\frac{\pi}{2}$", r"$\frac{3\pi}{4}$", r"$\pi$"]) >>> for ax, label in zip(axs, ("$f(x)$", "$f'(x)$", "$f''(x)$", "$f^{(3)}(x)$", "$f^{(4)}(x)$")): ... ax.set_ylabel(label) >>> labels = ['Interpolation nodes', 'True function $f$', 'Barycentric interpolation'] >>> axs[0].legend(axs[0].get_lines()[::-1], labels, bbox_to_anchor=(0., 1.02, 1., .102), ... loc='lower left', ncols=3, mode="expand", borderaxespad=0., frameon=False) >>> plt.show()
Далее мы покажем, как использование точек Чебышёва второго рода позволяет избежать явления Рунге. В этом примере мы также явно вычисляем веса.
>>> n = 20 >>> def f(x): return np.abs(x) + 0.5*x - x**2 >>> i = np.arange(n) >>> x_cheb = np.cos(i*np.pi/(n - 1)) # Chebyshev points on [-1, 1] >>> w_i_cheb = (-1.)**i # Explicit formula for weights of Chebyshev points >>> w_i_cheb[[0, -1]] /= 2 >>> p_cheb = BarycentricInterpolator(x_cheb, f(x_cheb), wi=w_i_cheb) >>> x_equi = np.linspace(-1, 1, n) >>> p_equi = BarycentricInterpolator(x_equi, f(x_equi)) >>> xx = np.linspace(-1, 1, 1000) >>> fig, ax = plt.subplots() >>> ax.plot(xx, f(xx), label="Original Function") >>> ax.plot(xx, p_cheb(xx), "--", label="Chebshev Points") >>> ax.plot(xx, p_equi(xx), "--", label="Equally Spaced Points") >>> ax.set(xlabel="$x$", ylabel="$f(x)$", xlim=[-1, 1]) >>> ax.legend() >>> plt.show()