多项式和样条插值

Machine LearningMachine LearningBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,我们将学习如何使用岭回归用一定次数的多项式逼近函数。给定一维点 x_in_samples,我们将展示两种不同的方法:

  1. PolynomialFeatures:生成指定次数以下的所有单项式。这为我们提供了一个具有 n_samples 行和 degree + 1 列的范德蒙德矩阵。
  2. SplineTransformer:生成B样条基函数。B样条的一个基函数是一个次数为 degree 的分段多项式函数,仅在 degree+1 个连续节点之间非零。

我们将使用 make_pipeline 函数添加非线性特征,并展示这些变换器如何非常适合用线性模型对非线性效应进行建模。我们将绘制函数、训练点以及使用多项式特征和B样条的插值。我们还将分别绘制两个变换器的所有列,并展示样条的节点。最后,我们将演示周期样条的使用。

虚拟机提示

虚拟机启动完成后,点击左上角切换到笔记本标签以访问Jupyter Notebook进行练习。

有时,你可能需要等待几秒钟让Jupyter Notebook完成加载。由于Jupyter Notebook的限制,操作的验证无法自动化。

如果你在学习过程中遇到问题,请随时向Labby提问。课程结束后提供反馈,我们将立即为你解决问题。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills ml/sklearn -.-> lab-49248{{"多项式和样条插值"}} end

准备数据

我们首先定义一个我们想要逼近的函数,并准备绘制它。

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

## 我们想要绘制的整个范围
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)

## 创建这些数组的二维数组版本,以便输入到变换器中
X_train = x_train[:, np.newaxis]
X_plot = x_plot[:, np.newaxis]

多项式特征插值

我们将使用 PolynomialFeatures 来生成多项式特征,并对训练数据拟合一个岭回归模型。然后,我们绘制函数、训练点以及使用多项式特征的插值。

## 绘制函数
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")

## 绘制训练点
ax.scatter(x_train, y_train, label="training points")

## 多项式特征
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}")

ax.legend(loc="lower center")
ax.set_ylim(-20, 10)
plt.show()

B样条插值

我们将使用 SplineTransformer 来生成B样条基函数,并对训练数据拟合一个岭回归模型。然后,我们绘制函数、训练点以及使用B样条的插值。

## 具有4 + 3 - 1 = 6个基函数的B样条
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()

绘制变换器

我们分别绘制两个变换器的所有列,以便更深入地了解生成的特征基。

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")

## 绘制样条的节点
knots = splt.bsplines_[0].t
axes[1].vlines(knots[3:-3], ymin=0, ymax=0.8, linestyles="dashed")
plt.show()

周期样条

我们通过使用 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)

## 将测试数据扩展到未来:
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()

总结

在本实验中,我们学习了如何使用岭回归用特定次数的多项式来逼近一个函数。给定一维点 x_in_samples,我们展示了两种不同的方法来实现这一点。我们使用 make_pipeline 函数来添加非线性特征,并演示了这些变换器如何非常适合用线性模型来建模非线性效应。我们绘制了函数、训练点以及使用多项式特征和B样条的插值。我们还分别绘制了两个变换器的所有列,并展示了样条的节点。最后,我们演示了周期样条的用法。