Spec-Zone.ru › scikit-learn

Примечание

Перейти к концу для скачивания полного примера кода. Или запустить этот пример в браузере через JupyterLite или Binder

Интерполяция многочленами и сплайнами

Этот пример демонстрирует, как приблизить функцию многочленами степени до degree с помощью регрессии с ненулевым штрафом. Мы показываем два разных способа, учитывая n_samples 1D точек x_i:

  • PolynomialFeatures генерирует все одночлены до degree. Это дает нам так называемую матрицу Вандермонда с n_samples строками и degree + 1 столбцами:

    [[1, x_0, x_0 ** 2, x_0 ** 3, ..., x_0 ** degree],
     [1, x_1, x_1 ** 2, x_1 ** 3, ..., x_1 ** degree],
     ...]
    

    Интуитивно эту матрицу можно интерпретировать как матрицу псевдопризнаков (точки, возведённые в некоторую степень). Матрица аналогична (но отличается от) матрицы, индуцированной полиномиальным ядром.

  • SplineTransformer генерирует базисные функции B-сплайнов. Базисная функция B-сплайна — это кусочно-полиномиальная функция степени degree, которая отлична от нуля только между degree+1 последовательными узлами. Учитывая n_knots количество узлов, это приводит к матрице с n_samples строками и n_knots + degree - 1 столбцами:

    [[basis_1(x_0), basis_2(x_0), ...],
     [basis_1(x_1), basis_2(x_1), ...],
     ...]
    

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

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

import matplotlib.pyplot as plt
import numpy as np

from sklearn.linear_model import Ridge
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures, SplineTransformer

Мы начнём с определения функции, которую мы намерены аппроксимировать, и подготовим её для построения графика.

def f(x):
    """Function to be approximated by polynomial interpolation."""
    return x * np.sin(x)


# whole range we want to plot
x_plot = np.linspace(-1, 11, 100)

Для большей наглядности мы предоставим только небольшую подвыборку точек для обучения.

x_train = np.linspace(0, 10, 100)
rng = np.random.RandomState(0)
x_train = np.sort(rng.choice(x_train, size=20, replace=False))
y_train = f(x_train)

# create 2D-array versions of these arrays to feed to transformers
X_train = x_train[:, np.newaxis]
X_plot = x_plot[:, np.newaxis]

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

# plot function
lw = 2
fig, ax = plt.subplots()
ax.set_prop_cycle(
    color=["black", "teal", "yellowgreen", "gold", "darkorange", "tomato"]
)
ax.plot(x_plot, f(x_plot), linewidth=lw, label="ground truth")

# plot training points
ax.scatter(x_train, y_train, label="training points")

# polynomial features
for degree in [3, 4, 5]:
    model = make_pipeline(PolynomialFeatures(degree), Ridge(alpha=1e-3))
    model.fit(X_train, y_train)
    y_plot = model.predict(X_plot)
    ax.plot(x_plot, y_plot, label=f"degree {degree}")

# B-spline with 4 + 3 - 1 = 6 basis functions
model = make_pipeline(SplineTransformer(n_knots=4, degree=3), Ridge(alpha=1e-3))
model.fit(X_train, y_train)

y_plot = model.predict(X_plot)
ax.plot(x_plot, y_plot, label="B-spline")
ax.legend(loc="lower center")
ax.set_ylim(-20, 10)
plt.show()
plot polynomial interpolation

Это хорошо демонстрирует, что многочлены более высокой степени могут лучше подогнать данные. Но в то же время, слишком высокие степени могут продемонстрировать нежелательное колебательное поведение и особенно опасны для экстраполяции за пределы диапазона аппроксимируемых данных. В этом преимущество B-сплайнов. Они обычно так же хорошо подгоняют данные, как и многочлены, и демонстрируют очень хорошее и плавное поведение. Они также имеют хорошие возможности для контроля экстраполяции, которая по умолчанию продолжается с константой. Обратите внимание, что чаще всего вы хотели бы увеличить количество узлов, но сохранить degree=3.

Чтобы получить более глубокое понимание сгенерированных базисов признаков, мы построим графики всех столбцов обоих преобразователей по отдельности.

fig, axes = plt.subplots(ncols=2, figsize=(16, 5))
pft = PolynomialFeatures(degree=3).fit(X_train)
axes[0].plot(x_plot, pft.transform(X_plot))
axes[0].legend(axes[0].lines, [f"degree {n}" for n in range(4)])
axes[0].set_title("PolynomialFeatures")

splt = SplineTransformer(n_knots=4, degree=3).fit(X_train)
axes[1].plot(x_plot, splt.transform(X_plot))
axes[1].legend(axes[1].lines, [f"spline {n}" for n in range(6)])
axes[1].set_title("SplineTransformer")

# plot knots of spline
knots = splt.bsplines_[0].t
axes[1].vlines(knots[3:-3], ymin=0, ymax=0.8, linestyles="dashed")
plt.show()
PolynomialFeatures, SplineTransformer

На левом графике мы распознаём линии, соответствующие простым одночленам от x**0 до x**3. На правом рисунке мы видим шесть базисных функций B-сплайна степени degree=3 и также четыре позиции узлов, выбранные во время fit. Обратите внимание, что слева и справа от области аппроксимации расположены ещё degree дополнительных узлов. Они необходимы по техническим причинам, поэтому мы их не отображаем. Каждая базисная функция имеет локальную поддержку и продолжается как константа за пределами области аппроксимации. Это поведение при экстраполяции можно изменить аргументом extrapolation.

Периодические сплайны

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

Периодические сплайны также могут быть полезны для естественно периодических признаков (таких как день года), так как плавность в граничных узлах предотвращает скачок в преобразованных значениях (например, от 31 декабря к 1 января). Для таких естественно периодических признаков или, более общим образом, для признаков, где период известен, рекомендуется явно передавать эту информацию в SplineTransformer путём ручного задания узлов.

def g(x):
    """Function to be approximated by periodic spline interpolation."""
    return np.sin(x) - 0.7 * np.cos(x * 3)


y_train = g(x_train)

# Extend the test data into the future:
x_plot_ext = np.linspace(-1, 21, 200)
X_plot_ext = x_plot_ext[:, np.newaxis]

lw = 2
fig, ax = plt.subplots()
ax.set_prop_cycle(color=["black", "tomato", "teal"])
ax.plot(x_plot_ext, g(x_plot_ext), linewidth=lw, label="ground truth")
ax.scatter(x_train, y_train, label="training points")

for transformer, label in [
    (SplineTransformer(degree=3, n_knots=10), "spline"),
    (
        SplineTransformer(
            degree=3,
            knots=np.linspace(0, 2 * np.pi, 10)[:, None],
            extrapolation="periodic",
        ),
        "periodic spline",
    ),
]:
    model = make_pipeline(transformer, Ridge(alpha=1e-3))
    model.fit(X_train, y_train)
    y_plot_ext = model.predict(X_plot_ext)
    ax.plot(x_plot_ext, y_plot_ext, label=label)

ax.legend()
fig.show()
plot polynomial interpolation
fig, ax = plt.subplots()
knots = np.linspace(0, 2 * np.pi, 4)
splt = SplineTransformer(knots=knots[:, None], degree=3, extrapolation="periodic").fit(
    X_train
)
ax.plot(x_plot_ext, splt.transform(X_plot_ext))
ax.legend(ax.lines, [f"spline {n}" for n in range(3)])
plt.show()
plot polynomial interpolation

Общее время выполнения скрипта: (0 минут 0,443 секунды)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_polynomial_interpolation.ipynb

Download Python source code: plot_polynomial_interpolation.py

Download zipped: plot_polynomial_interpolation.zip

Похожие примеры

Сравнение линейных байесовских регрессоров

Инженерия временных признаков

Недообучение против переобучения

Основные моменты выпуска scikit-learn 1.0

© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/linear_model/plot_polynomial_interpolation.html

Spec-Zone.ru

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