Моя цель — рассчитать плавную траекторию, проходящую через набор точек, как показано ниже. Я просмотрел доступные методы scipy.interpolate , а также руководство пользователя scipy. Однако выбор правильного метода мне не совсем ясен.
В чем разница между BSpline, splprep, splrep, Одномерный Сплайн, interp1d, make_interp_spline и КубическийСплайн?
Согласно документации, все функции вычисляют некоторую полиномиальную сплайн-функцию через последовательность входных точек. Какую функцию мне выбрать? А) Чем кубический сплайн отличается от B-сплайна третьего порядка? Б) В чем разница между splprep() и splrep()? В) Почему interp1d() станет устаревшим?
Я знаю, что задаю здесь разные вопросы, но не вижу смысла разделять вопросы, поскольку предполагаю, что ответы будут связаны.
В целом я считаю, что модуль scipy.interpolate организован немного запутанно. Я подумал, может быть, я не единственный, у кого сложилось такое впечатление, поэтому я обращаюсь к SO.
Вот как далеко я зашел. Ниже приведен код, который запускает различные функции сплайна для некоторых тестовых данных. Это создает фигуру ниже.
CublicSpline и любой из методов B-сплайна?BSpline из результатов splprep и splrep так, чтобы результаты splev() и BSpline() были эквивалентны. Таким образом, мы можем преобразовать вывод splrep и splprep в объектно-ориентированный интерфейс scipy.interpolate().splrep, UnivariateSpline и make_interp_spline приводят к одному и тому же результату. В моих 2D-данных мне нужно применять интерполяцию независимо для каждого измерения данных, с которым она работает. Функция удобства interp1d также дает тот же результат. Связанный SO-вопрос: Ссылкаsplprep и splrep кажутся не связанными. Даже если я вычислю splprep дважды для каждой оси данных независимо (см. p0_new), результат будет выглядеть по-другому. В документации я вижу, что splprep вычисляет B-сплайн-представление кривой n-D. Но не должны ли splrep и splprep быть связаны?splprep, splrep и UnivariateSpline имеют параметр сглаживания, тогда как у других интерполяторов такого параметра нет.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()






В чем разница между 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.
В1: не банкомат. Однако легко сделать своими руками: docs.scipy.org/doc/scipy/tutorial/interpolate/…
Вопрос 2: очень похоже. Параметрический случай просто требует дополнительного суммирования по компонентам. См. раздел «Примечания» на странице github.com/scipy/scipy/pull/19970/… --- Я считаю, что это точное повторение кода FITPACK и статьи Dietckx 1982 года (также упоминаемой в доктринах scipy PR).
Говоря о пикантном пиаре, отзывы пользователей приветствуются.
Ого, большое спасибо за такие разъяснения. Я думаю, что для вычисления плавной траектории в n-d мне следует использовать параметрическую форму. Два немедленных дополнительных вопроса: Q1) Есть ли в scipy.interpolate интерфейс «более высокого уровня» для параметризованных интерполяторов, аналогичный
make_interp_spline(), или мне придется прибегнуть кsplprep()? Вопрос 2) Отличается ли математика междуsplprep()иsplrep? Я имею в виду, не могу ли я объединить n независимыхsplrep()оценок, чтобы получить x1(u), x2(u),... с uε[0,1]. Илиsplprep()решает другую проблему?