降维是一种无监督学习技术。
然而,它可以作为机器学习算法在分类和回归预测建模数据集上的数据转换预处理步骤,用于监督学习算法。
有许多降维算法可供选择,没有一种算法适用于所有情况。相反,探索一系列降维算法和每种算法的不同配置是一个好主意。
在本教程中,您将了解如何在 Python 中拟合和评估顶级降维算法。
完成本教程后,您将了解:
- 降维旨在找到数值输入数据的低维表示,同时保留数据中的重要关系。
- 有许多不同的降维算法,没有一种方法适用于所有数据集。
- 如何在 Python 中使用 scikit-learn 机器学习库实现、拟合和评估顶级降维。
立即开始您的项目,阅读我的新书《机器学习数据准备》,其中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。

Python 降维算法
照片来源:Bernard Spragg. NZ,部分权利保留。
教程概述
本教程分为三个部分;它们是:
- 降维
- 降维算法
- 降维示例
- Scikit-Learn 库安装
- 分类数据集
- 主成分分析
- 奇异值分解
- 线性判别分析
- Isomap 嵌入
- 局部线性嵌入
- 改进型局部线性嵌入
降维
降维是指在训练数据中减少输入变量数量的技术。
在处理高维数据时,通过将数据投影到捕获数据“本质”的低维子空间来降低维度通常很有用。这被称为降维。
— 第 11 页,《机器学习:概率视角》,2012 年。
高维度可能意味着有数百、数千甚至数百万个输入变量。
更少的输入维度通常意味着更少的参数或更简单的机器学习模型结构,这被称为自由度。具有过多自由度的模型很可能过拟合训练数据集,并且在新数据上的表现可能不佳。
理想的模型应具有泛化能力强且简洁的特点,反过来,输入数据应具有较少的输入变量。这对于线性模型尤其重要,因为输入数量和模型自由度通常密切相关。
降维是在建模之前对数据执行的数据准备技术。它可能在数据清理和数据缩放之后,在训练预测模型之前执行。
……降维技术能够产生更紧凑、更易于解释的目标概念表示,并将用户的注意力集中在最相关的变量上。
— 第 289 页,《数据挖掘:实用机器学习工具和技术》,第 4 版,2016 年。
因此,在训练数据上进行的任何降维操作也必须在新数据上进行,例如测试数据集、验证数据集以及使用最终模型进行预测时的数据。
想开始学习数据准备吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
降维算法
有许多可用于降维的算法。
主要的两类方法是那些源于线性代数的方法和那些源于流形学习的方法。
线性代数方法
源自线性代数领域的矩阵分解方法可用于降维。
有关矩阵分解的更多信息,请参阅教程
一些更流行的方法包括
- 主成分分析
- 奇异值分解
- 非负矩阵分解
流形学习方法
流形学习方法旨在找到高维输入的低维投影,这些投影能够捕捉输入数据的关键特性。
一些更流行的方法包括
- Isomap 嵌入
- 局部线性嵌入
- 多维尺度分析
- 谱嵌入
- t-分布随机邻域嵌入
每种算法都提供了一种不同的方法来应对在低维度下发现数据自然关系这一挑战。
没有最佳的降维算法,也没有简单的方法可以在不进行受控实验的情况下找到适合您数据的最佳算法。
在本教程中,我们将回顾如何使用 scikit-learn 库中的这些流行降维算法的每个子集。
这些示例将为您提供复制粘贴示例并在您自己的数据上测试这些方法的基础。
我们不会深入探讨算法工作原理的理论,也不会直接比较它们。有关此主题的良好起点,请参阅
让我们开始吧。
降维示例
在本节中,我们将回顾如何在 scikit-learn 中使用流行的降维算法。
这包括一个将降维技术用作建模管道中的数据转换的示例,以及评估在数据上拟合的模型。
这些示例旨在供您复制粘贴到您自己的项目中并应用于您自己的数据。scikit-learn 库中提供了一些算法,但由于算法本身的性质无法直接用作数据转换,因此并未在此展示。
因此,我们将在每个示例中使用合成分类数据集。
Scikit-Learn 库安装
首先,让我们安装库。
不要跳过此步骤,您需要确保安装了最新版本。
您可以使用 pip Python 安装程序安装 scikit-learn 库,如下所示:
1 |
sudo pip install scikit-learn |
有关特定于您平台的其他安装说明,请参阅:
接下来,让我们确认已安装该库并正在使用现代版本。
运行以下脚本打印库版本号。
1 2 3 |
# 检查 scikit-learn 版本 import sklearn print(sklearn.__version__) |
运行该示例,您应该会看到以下版本号或更高版本。
1 |
0.23.0 |
分类数据集
我们将使用 make_classification() 函数来创建测试二分类数据集。
该数据集将包含 1,000 个样本,其中有 20 个输入特征,10 个是信息性的,10 个是冗余的。这为每种技术提供了识别和删除冗余输入特征的机会。
伪随机数生成器的固定随机种子确保我们每次运行代码时都会生成相同的合成数据集。
下面列出了创建和总结合成分类数据集的示例。
1 2 3 4 5 6 |
# 合成分类数据集 from sklearn.datasets import make_classification # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 汇总数据集 print(X.shape, y.shape) |
运行示例创建数据集并报告行数和列数,这与我们的预期相符。
1 |
(1000, 20) (1000,) |
这是一项二元分类任务,我们将在每次降维转换后评估一个逻辑回归模型。
模型将使用重复分层 10 折交叉验证的黄金标准进行评估。将报告所有折和重复之间的平均和标准差分类准确率。
以下示例将模型在原始数据集上的评估作为比较基准。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 在原始数据上评估逻辑回归模型 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 定义模型 model = LogisticRegression() # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例,使用所有 20 列对原始数据集上的逻辑回归进行评估,准确率约为 82.4%。
成功的降维转换应该能让模型获得比此基线更好的准确率,尽管并非所有技术都能实现这一点。
注意:我们不尝试“解决”这个数据集,只是提供可用的示例,您可以将其用作起点。
1 |
准确率:0.824 (0.034) |
接下来,我们可以开始查看降维算法在此数据集上的应用示例。
我已经对每种方法进行了最小的调整。每种降维方法都将被配置为将 20 个输入列减少到 10 个(如果可能)。
我们将使用管道 (Pipeline) 将数据转换和模型组合成一个原子单元,可以使用交叉验证程序对其进行评估;例如:
1 2 3 4 |
... # 定义管道 steps = [('pca', PCA(n_components=10)), ('m', LogisticRegression())] model = Pipeline(steps=steps) |
让我们开始吧。
您能为其中一种算法获得更好的结果吗?
在下面的评论中告诉我。
主成分分析
主成分分析(PCA)可能是稠密数据(零值很少)降维最常用的技术。
有关 PCA 工作原理的更多信息,请参阅教程
scikit-learn 库提供了PCA 类,这是主成分分析的实现,可用作降维数据转换。“n_components”参数可以设置为配置转换输出所需的维度数。
下面列出了使用 PCA 降维评估模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用 PCA 和逻辑回归算法进行分类评估 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.pipeline import Pipeline 从 sklearn.分解 导入 PCA 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 定义管道 steps = [('pca', PCA(n_components=10)), ('m', LogisticRegression())] model = Pipeline(steps=steps) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例将评估包含降维和逻辑回归预测模型的建模管道。
注意:由于算法的随机性或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,我们没有看到使用 PCA 转换对模型性能有任何提升。
1 |
准确率:0.824 (0.034) |
奇异值分解
奇异值分解(SVD)是降维技术中最常用的技术之一,特别适用于稀疏数据(许多值为零的数据)。
有关 SVD 工作原理的更多信息,请参阅教程
scikit-learn 库提供了TruncatedSVD 类,这是奇异值分解的实现,可用作降维数据转换。“n_components”参数可以设置为配置转换输出所需的维度数。
下面列出了使用 SVD 降维评估模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用 SVD 和逻辑回归算法进行分类评估 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.pipeline import Pipeline from sklearn.decomposition import TruncatedSVD 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 定义管道 steps = [('svd', TruncatedSVD(n_components=10)), ('m', LogisticRegression())] model = Pipeline(steps=steps) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例将评估包含降维和逻辑回归预测模型的建模管道。
注意:由于算法的随机性或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,我们没有看到使用 SVD 转换对模型性能有任何提升。
1 |
准确率:0.824 (0.034) |
线性判别分析
线性判别分析(LDA)是一种多类别分类算法,可用于降维。
投影的维度数量限制为 1 和 C-1,其中 C 是类别的数量。在这种情况下,我们的数据集是二元分类问题(两个类别),将维度数量限制为 1。
有关 LDA 用于降维的更多信息,请参阅教程
scikit-learn 库提供了LinearDiscriminantAnalysis 类,这是线性判别分析的实现,可用作降维数据转换。“n_components”参数可以设置为配置转换输出所需的维度数。
下面列出了使用 LDA 降维评估模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用 LDA 和逻辑回归算法进行分类评估 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.pipeline import Pipeline from sklearn.discriminant_analysis import LinearDiscriminantAnalysis 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 定义管道 steps = [('lda', LinearDiscriminantAnalysis(n_components=1)), ('m', LogisticRegression())] model = Pipeline(steps=steps) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例将评估包含降维和逻辑回归预测模型的建模管道。
注意:由于算法的随机性或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,与在原始数据上拟合的基线相比,我们可以看到性能有轻微提升。
1 |
准确率:0.825 (0.034) |
Isomap 嵌入
Isomap 嵌入,或 Isomap,创建数据集的嵌入,并尝试保留数据中的关系。
scikit-learn 库提供了Isomap 类,这是 Isomap 嵌入的实现,可用作降维数据转换。“n_components”参数可以设置为配置转换输出所需的维度数。
下面列出了使用 SVD 降维评估模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用 Isomap 和逻辑回归算法进行分类评估 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.pipeline import Pipeline from sklearn.manifold import Isomap 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 定义管道 steps = [('iso', Isomap(n_components=10)), ('m', LogisticRegression())] model = Pipeline(steps=steps) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例将评估包含降维和逻辑回归预测模型的建模管道。
注意:由于算法的随机性或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,与在原始数据上拟合的基线相比,我们可以看到 Isomap 数据转换的性能有所提升。
1 |
准确率:0.888 (0.029) |
局部线性嵌入
局部线性嵌入(LLE)创建数据集的嵌入,并尝试保留数据中邻域之间的关系。
scikit-learn 库提供了LocallyLinearEmbedding 类,这是局部线性嵌入的实现,可用作降维数据转换。“n_components”参数可以设置为配置转换输出所需的维度数。
下面列出了使用 LLE 降维评估模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用 LLE 和逻辑回归进行分类评估 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.pipeline import Pipeline from sklearn.manifold import LocallyLinearEmbedding 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 定义管道 steps = [('lle', LocallyLinearEmbedding(n_components=10)), ('m', LogisticRegression())] model = Pipeline(steps=steps) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例将评估包含降维和逻辑回归预测模型的建模管道。
注意:由于算法的随机性或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,与在原始数据上拟合的基线相比,我们可以看到 LLE 数据转换的性能有所提升。
1 |
准确率:0.886 (0.028) |
改进型局部线性嵌入
改进型局部线性嵌入(Modified LLE)是局部线性嵌入的扩展,它为每个邻域创建多个加权向量。
scikit-learn 库提供了LocallyLinearEmbedding 类,这是改进型局部线性嵌入的实现,可用作降维数据转换。“method”参数必须设置为‘modified’,而“n_components”参数可以设置为配置转换输出所需的维度数,该维度数必须小于“n_neighbors”参数。
下面列出了使用改进型 LLE 降维评估模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用改进型 LLE 和逻辑回归进行分类评估 from numpy import mean from numpy import std from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.pipeline import Pipeline from sklearn.manifold import LocallyLinearEmbedding 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7) # 定义管道 steps = [('lle', LocallyLinearEmbedding(n_components=5, method='modified', n_neighbors=10)), ('m', LogisticRegression())] model = Pipeline(steps=steps) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1) # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例将评估包含降维和逻辑回归预测模型的建模管道。
注意:由于算法的随机性或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,与在原始数据上拟合的基线相比,我们可以看到改进型 LLE 数据转换的性能有所提升。
1 |
准确率:0.846 (0.036) |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
API
总结
在本教程中,您了解了如何在 Python 中拟合和评估顶级降维算法。
具体来说,你学到了:
- 降维旨在找到数值输入数据的低维表示,同时保留数据中的重要关系。
- 有许多不同的降维算法,没有一种方法适用于所有数据集。
- 如何在 Python 中使用 scikit-learn 机器学习库实现、拟合和评估顶级降维。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
如何选择维度数量
一些方法会提供关于组件/维度数量有用的信息,例如 PCA。
通常,将其视为建模管道的超参数。
文章没有提到哪些输入被丢弃,哪些可以被认为是“强”的。在实际场景中,有必要了解这些信息来证明降维的合理性。
我根据结果来指导我。例如,使用能产生最佳模型性能的维度数量。
UMAP也是一种很棒的降维算法。
谢谢!
我尝试过使用 UMAP 来可视化我的数据。您能否提供一些关于如何将其用作降维算法的见解?
你好 Jason。流形方法中的任何一种都可以用于时间序列数据吗?
也许吧,我对时间序列聚类不太了解,抱歉。
嗨,Jason,
在进行 K-Means 聚类之前,使用线性判别分析降维技术来减少维度数量是否有任何问题?
我尝试了 PCA + K-Means 和 LDA + K-Means。我为 LDA + K-Means 获得了良好的结果。但我找不到任何使用 LDA + K-Means 的工作。由于我正在处理一个标记数据集,我可以采用 LDA 技术,但在实际情况中,可能没有标记数据集。所以我的问题是,如果我使用 LDA + K-Means 是否有意义?我没有找到任何使用这种技术进行聚类的作品。
谢谢您
我认为这很有意义。另外,我也可以看到一些关于 LDA+KMeans 的学术工作(https://journals.sagepub.com/doi/full/10.1155/2015/491910)!
Jason,我在这里有点迷茫,关于降维,我们是否先使用 PCA + 逻辑回归来找到降维的准确性,然后再使用另一个模型来训练和测试数据?
PCA 是一种降维技术。但任何降维都会丢失一些信息,只是信息量多少的问题。例如,应用逻辑回归可以帮助您找到一种方法来衡量降维是否能保留您在特定问题所需的信息。
谢谢。
大家好,
是否有与 PLA(分段线性近似)相关的技术可用于降维?我遇到的问题是:我的数据集是一个矩阵,其中包含时间序列,每一行代表一个时间序列。我需要一个使用 PLA 来减少列数的算法。
谢谢并致以最诚挚的问候
Med
Med,您好……以下讨论是关于这个主题的一个很棒的资源:
https://stackoverflow.com/questions/29382903/how-to-apply-piecewise-linear-fit-in-python
您好,我尝试使用谱嵌入来查看交叉验证分数,但它返回了 nan 值。您能帮我看看哪里出错了 G 吗?谢谢,Sarka
# 谱嵌入
from sklearn import metrics
from sklearn.datasets import load_digits
from sklearn.manifold import SpectralEmbedding
from sklearn.metrics import accuracy_score
# 定义数据集
X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=7)
# 定义管道
model = SpectralEmbedding(n_components=2)
X_transformed = model.fit_transform(X)
# 评估模型
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring=’accuracy’, cv=cv, n_jobs=-1)
# 报告表现
print(‘Accuracy: %.3f (%.3f)’ % (mean(n_scores), std(n_scores)))
Sarka,您好……我没有看到您定义 `make_classification` 的地方。
我有一个问题,如果我的数据集中包含分类变量和数值变量,您推荐使用哪种技术,或者在这些情况下我应该怎么做?谢谢。
Bryam,您好……以下讨论可能对您感兴趣。
https://datascience.stackexchange.com/questions/103039/which-machine-learning-model-is-best-for-a-combination-of-numerical-and-categori