注意
转到结尾 下载完整的示例代码。或者通过JupyterLite或Binder在浏览器中运行此示例
主成分回归与偏最小二乘回归#
本例比较了主成分回归(PCR)和偏最小二乘回归(PLS)在一个玩具数据集上。我们的目标是说明当目标与数据中某些低方差方向强烈相关时,PLS如何优于PCR。
PCR是一个由两步组成的回归器:首先,PCA
应用于训练数据,可能进行降维;然后,在变换后的样本上训练一个回归器(例如线性回归器)。在PCA
中,变换是纯无监督的,这意味着不使用关于目标的任何信息。结果,在目标与具有低方差的 *方向* 强烈相关的某些数据集中,PCR 的性能可能很差。事实上,PCA 的降维将数据投影到一个低维空间中,在该空间中,投影数据的方差沿每个轴贪婪地最大化。尽管它们对目标具有最大的预测能力,但方差较低的这些方向将被丢弃,最终的回归器将无法利用它们。
PLS 既是变换器又是回归器,它与 PCR 非常相似:它还在应用线性回归器到变换数据之前对样本进行降维。与 PCR 的主要区别在于 PLS 变换是监督的。因此,正如我们将在本例中看到的,它不会受到我们刚才提到的问题的影响。
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
数据#
我们首先创建一个具有两个特征的简单数据集。在我们深入研究 PCR 和 PLS 之前,我们先拟合一个 PCA 估计器来显示该数据集的两个主成分,即解释数据中最大方差的两个方向。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA
rng = np.random.RandomState(0)
n_samples = 500
cov = [[3, 3], [3, 4]]
X = rng.multivariate_normal(mean=[0, 0], cov=cov, size=n_samples)
pca = PCA(n_components=2).fit(X)
plt.scatter(X[:, 0], X[:, 1], alpha=0.3, label="samples")
for i, (comp, var) in enumerate(zip(pca.components_, pca.explained_variance_)):
comp = comp * var # scale component by its variance explanation power
plt.plot(
[0, comp[0]],
[0, comp[1]],
label=f"Component {i}",
linewidth=5,
color=f"C{i + 2}",
)
plt.gca().set(
aspect="equal",
title="2-dimensional dataset with principal components",
xlabel="first feature",
ylabel="second feature",
)
plt.legend()
plt.show()
出于本例的目的,我们现在定义目标y
,使其与具有小方差的方向强烈相关。为此,我们将X
投影到第二个成分上,并为其添加一些噪声。
y = X.dot(pca.components_[1]) + rng.normal(size=n_samples) / 2
fig, axes = plt.subplots(1, 2, figsize=(10, 3))
axes[0].scatter(X.dot(pca.components_[0]), y, alpha=0.3)
axes[0].set(xlabel="Projected data onto first PCA component", ylabel="y")
axes[1].scatter(X.dot(pca.components_[1]), y, alpha=0.3)
axes[1].set(xlabel="Projected data onto second PCA component", ylabel="y")
plt.tight_layout()
plt.show()
在一个成分上的投影和预测能力#
我们现在创建两个回归器:PCR 和 PLS,并且为了说明目的,我们将成分数量设置为 1。在将数据馈送到 PCR 的 PCA 步骤之前,我们首先对其进行标准化,这是良好实践的推荐做法。PLS 估计器具有内置的缩放功能。
对于这两个模型,我们将投影到第一个成分上的数据与目标作图。在这两种情况下,投影数据都是回归器将用作训练数据的数据。
from sklearn.cross_decomposition import PLSRegression
from sklearn.decomposition import PCA
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=rng)
pcr = make_pipeline(StandardScaler(), PCA(n_components=1), LinearRegression())
pcr.fit(X_train, y_train)
pca = pcr.named_steps["pca"] # retrieve the PCA step of the pipeline
pls = PLSRegression(n_components=1)
pls.fit(X_train, y_train)
fig, axes = plt.subplots(1, 2, figsize=(10, 3))
axes[0].scatter(pca.transform(X_test), y_test, alpha=0.3, label="ground truth")
axes[0].scatter(
pca.transform(X_test), pcr.predict(X_test), alpha=0.3, label="predictions"
)
axes[0].set(
xlabel="Projected data onto first PCA component", ylabel="y", title="PCR / PCA"
)
axes[0].legend()
axes[1].scatter(pls.transform(X_test), y_test, alpha=0.3, label="ground truth")
axes[1].scatter(
pls.transform(X_test), pls.predict(X_test), alpha=0.3, label="predictions"
)
axes[1].set(xlabel="Projected data onto first PLS component", ylabel="y", title="PLS")
axes[1].legend()
plt.tight_layout()
plt.show()
正如预期的那样,PCR 的无监督 PCA 变换已经丢弃了第二个成分,即方差最小的方向,尽管它是预测能力最强的方向。这是因为 PCA 是一种完全无监督的变换,并且导致投影数据对目标的预测能力较低。
另一方面,PLS 回归器由于在变换过程中使用了目标信息,因此能够捕获方差最小的方向的影响:它可以识别出这个方向实际上是预测能力最强的方向。我们注意到第一个 PLS 分量与目标负相关,这是因为特征向量的符号是任意的。
我们还打印了两个估计器的 R 平方分数,这进一步证实了在这种情况下的 PLS 比 PCR 更好。负 R 平方表示 PCR 的性能比仅预测目标均值的回归器更差。
print(f"PCR r-squared {pcr.score(X_test, y_test):.3f}")
print(f"PLS r-squared {pls.score(X_test, y_test):.3f}")
PCR r-squared -0.026
PLS r-squared 0.658
最后,我们注意到具有 2 个成分的 PCR 的性能与 PLS 一样好:这是因为在这种情况下,PCR 能够利用对目标具有最大预测能力的第二个成分。
pca_2 = make_pipeline(PCA(n_components=2), LinearRegression())
pca_2.fit(X_train, y_train)
print(f"PCR r-squared with 2 components {pca_2.score(X_test, y_test):.3f}")
PCR r-squared with 2 components 0.673
脚本总运行时间:(0 分钟 0.527 秒)
相关示例