В чем разница между различными сплайн-интерполяторами от Scipy?

Моя цель — рассчитать плавную траекторию, проходящую через набор точек, как показано ниже. Я просмотрел доступные методы scipy.interpolate , а также руководство пользователя scipy. Однако выбор правильного метода мне не совсем ясен.

В чем разница между BSpline, splprep, splrep, Одномерный Сплайн, interp1d, make_interp_spline и КубическийСплайн?

Согласно документации, все функции вычисляют некоторую полиномиальную сплайн-функцию через последовательность входных точек. Какую функцию мне выбрать? А) Чем кубический сплайн отличается от B-сплайна третьего порядка? Б) В чем разница между splprep() и splrep()? В) Почему interp1d() станет устаревшим?

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

В целом я считаю, что модуль scipy.interpolate организован немного запутанно. Я подумал, может быть, я не единственный, у кого сложилось такое впечатление, поэтому я обращаюсь к SO.


Вот как далеко я зашел. Ниже приведен код, который запускает различные функции сплайна для некоторых тестовых данных. Это создает фигуру ниже.

  1. Я где-то читал: «Все кубические сплайны могут быть представлены как B-сплайны третьего порядка», и что «какое представление удобнее, это вопрос перспективы». Но почему я получаю разные результаты, если использую CublicSpline и любой из методов B-сплайна?
  2. Я обнаружил, что можно построить объект BSpline из результатов splprep и splrep так, чтобы результаты splev() и BSpline() были эквивалентны. Таким образом, мы можем преобразовать вывод splrep и splprep в объектно-ориентированный интерфейс scipy.interpolate().
  3. splrep, UnivariateSpline и make_interp_spline приводят к одному и тому же результату. В моих 2D-данных мне нужно применять интерполяцию независимо для каждого измерения данных, с которым она работает. Функция удобства interp1d также дает тот же результат. Связанный SO-вопрос: Ссылка
  4. splprep и splrep кажутся не связанными. Даже если я вычислю splprep дважды для каждой оси данных независимо (см. p0_new), результат будет выглядеть по-другому. В документации я вижу, что splprep вычисляет B-сплайн-представление кривой n-D. Но не должны ли splrep и splprep быть связаны?
  5. splprep, splrep и UnivariateSpline имеют параметр сглаживания, тогда как у других интерполяторов такого параметра нет.
  6. splrep сочетается с UnivariateSpline. Однако я не смог найти подходящего объектно-ориентированного аналога для splprep. Есть ли такой?

import numpy as np
from scipy.interpolate import *
import matplotlib.pyplot as plt

points = [[0, 0], [4, 4], [-1, 9], [-4, -1], [-1, -9], [4, -4], [0, 0]]
points = np.asarray(points)

n = 50 
ts = np.linspace(0, 1, len(points))
ts_new = np.linspace(0, 1, n)

(t0_0,c0_0,k0_0), u = splprep(points[:,[0]].T, s=0, k=3)
(t0_1,c0_1,k0_1), u = splprep(points[:,[1]].T, s=0, k=3)
p0_new = np.r_[np.asarray(splev(ts_new, (t0_0,c0_0,k0_0))),
               np.asarray(splev(ts_new, (t0_1,c0_1,k0_1))),
                ].T

# splprep/splev
(t1,c1,k1), u = splprep(points.T, s=0, k=3)
p1_new = splev(ts_new, (t1,c1,k1))
# BSpline from splprep
p2_new = BSpline(t1, np.asarray(c1).T, k=k1)(ts_new)
# splrep/splev (per dimension)
(t3_0,c3_0,k3_0) = splrep(ts, points[:,0].T, s=0, k=3)
(t3_1,c3_1,k3_1) = splrep(ts, points[:,1].T, s=0, k=3)
p3_new = np.c_[splev(ts_new, (t3_0,c3_0,k3_0)),
               splev(ts_new, (t3_1,c3_1,k3_1)),
               ]
# Bspline from splrep
p4_new = np.c_[BSpline(t3_0, np.asarray(c3_0), k=k3_0)(ts_new),
               BSpline(t3_1, np.asarray(c3_1), k=k3_1)(ts_new),
               ]
# UnivariateSpline
p5_new = np.c_[UnivariateSpline(ts, points[:,0], s=0, k=3)(ts_new),
               UnivariateSpline(ts, points[:,1], s=0, k=3)(ts_new),]
# make_interp_spline
p6_new = make_interp_spline(ts, points, k=3)(ts_new)
# CubicSpline
p7_new = CubicSpline(ts, points, bc_type = "clamped")(ts_new)
# interp1d
p8_new = interp1d(ts, points.T, kind = "cubic")(ts_new).T

fig, ax = plt.subplots()
ax.plot(*points.T, "o-", label = "Original points")
ax.plot(*p1_new,   "o-", label = "1: splprep/splev")
ax.plot(*p2_new.T, "x-", label = "1: BSpline from splprep")
ax.plot(*p3_new.T, "o-", label = "2: splrep/splev")
ax.plot(*p4_new.T, "x-", label = "2: BSpline from splrep")
ax.plot(*p5_new.T, "*-", label = "2: UnivariateSpline")
ax.plot(*p6_new.T, "+-", label = "2: make_interp_spline")
ax.plot(*p7_new.T, "x-", label = "3: CubicSpline")
#ax.plot(*p8_new.T, "k+-", label = "3: interp1d")
#ax.plot(*p0_new.T, "k+-", label = "3: CubicSpline")
ax.set_aspect("equal")
ax.grid("on")
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
549
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В чем разница между BSpline, splprep, splrep, UnivariateSpline, interp1d, make_interp_spline и CubicSpline?

  • Объект BSpline представляет собой сплайн-функцию с точки зрения узлов t, коэффициентов c и степени k. Он ничего не знает о данных x, y. Это объект реализации низкого уровня, наравне с PPoly --- думайте о PPoly и Bspline как об изменении базиса.

  • make_interp_spline создает сплайн (BSpline), который проходит через данные x и y — это интерполирующий сплайн, так что spl(x) == y. Он может обрабатывать пакеты данных: если y двумерен, а второе измерение имеет длину n, make_interp_spline(x, y) представляет собой стек функций y_1(x), y_2(x), ..., y_n(x).

  • CubicSpline аналогичен, но более ограничен: он допускает только кубические сплайны, k=3. Если вам когда-нибудь понадобится переключиться с кубиков на, например. линейная интерполяция: с помощью make_interp_spline вы просто меняете k=3 на k=1 в месте вызова. OTOH, CubicSpline имеет некоторые функции, которых нет у BSpline: например. поиск корней. Это экземпляр PPoly, а не BSPline.

  • interp1d не устарел, он унаследован. Полезная часть interp1d — режимы «ближайший/предыдущий/следующий». Остальное просто делегирует make_interp_spline, поэтому лучше использовать его напрямую.

  • splrep строит сглаживающую сплайн-функцию по данным. Степень сглаживания контролируется параметром s, где s=0 означает интерполяцию. Он возвращает не BSpline, а кортеж tck (узлы, коэффициенты и степень).

  • splprep строит сглаживающую сплайн-кривую в параметрической форме. То есть (x(u), y(u)) не y(x). Также возвращает tck-кортежи.

  • UnivariateSpline эквивалентно splrep.

Обратите внимание, что scipy.interpolate вырос органически. Имея как минимум четыре поколения разработчиков за почти четверть века. А библиотека FITPACK, которой делегируют splrep, splprep и UnivariateSpline, датируется 1980-ми годами. CubicSpline, BSpline и make_interp_spline не используют FITPACK.

Поэтому в новом коде я бы лично рекомендовал make_interp_spline + BSpline; если вам нужны только кубики, CubicSpline тоже подойдет.

Но почему я получаю разные результаты, если использую CublicSpline и любой из методов B-сплайна?

Граничные условия. По умолчанию для make_interp_spline и CubicSpline установлено значение not-a-knot, и вы можете его изменить. splrep и др. используют только not-a-knot.

Ого, большое спасибо за такие разъяснения. Я думаю, что для вычисления плавной траектории в n-d мне следует использовать параметрическую форму. Два немедленных дополнительных вопроса: Q1) Есть ли в scipy.interpolate интерфейс «более высокого уровня» для параметризованных интерполяторов, аналогичный make_interp_spline(), или мне придется прибегнуть к splprep()? Вопрос 2) Отличается ли математика между splprep() и splrep? Я имею в виду, не могу ли я объединить n независимых splrep() оценок, чтобы получить x1(u), x2(u),... с uε[0,1]. Или splprep() решает другую проблему?

normanius 25.02.2024 12:34

В1: не банкомат. Однако легко сделать своими руками: docs.scipy.org/doc/scipy/tutorial/interpolate/…

ev-br 25.02.2024 14:11

Вопрос 2: очень похоже. Параметрический случай просто требует дополнительного суммирования по компонентам. См. раздел «Примечания» на странице github.com/scipy/scipy/pull/19970/… --- Я считаю, что это точное повторение кода FITPACK и статьи Dietckx 1982 года (также упоминаемой в доктринах scipy PR).

ev-br 25.02.2024 14:16

Говоря о пикантном пиаре, отзывы пользователей приветствуются.

ev-br 25.02.2024 14:17

Другие вопросы по теме