减少预测模型的输入变量数量被称为降维。
更少的输入变量可以生成更简单的预测模型,该模型在对新数据进行预测时可能具有更好的性能。
线性判别分析,简称 LDA,是一种用于多类别分类的预测建模算法。它也可以用作降维技术,提供训练数据集的投影,以最佳方式根据其分配的类别分离样本。
线性判别分析用于降维的能力常常让大多数实践者感到惊讶。
在本教程中,您将学习如何在开发预测模型时使用 LDA 进行降维。
完成本教程后,您将了解:
- 降维涉及减少建模数据中的输入变量或列的数量。
- LDA 是一种多类别分类技术,可用于自动执行降维。
- 如何评估使用 LDA 投影作为输入并使用新的原始数据进行预测的预测模型。
通过我的新书《机器学习数据准备》快速启动您的项目,包括分步教程和所有示例的 Python 源代码文件。
让我们开始吧。
- 2020 年 5 月更新:改进了代码注释

Python 中用于降维的线性判别分析
图片由 Kimberly Vardeman 提供,部分权利保留。
教程概述
本教程分为四个部分;它们是
- 降维
- 线性判别分析
- LDA Scikit-Learn API
- LDA 用于降维的实例
降维
降维指的是减少数据集的输入变量数量。
如果您的数据以行和列的形式表示,例如在电子表格中,那么输入变量就是作为模型输入以预测目标变量的列。输入变量也称为特征。
我们可以将数据的列视为n维特征空间中的维度,将数据的行视为该空间中的点。这是数据集的一个有用的几何解释。
在具有 k 个数值属性的数据集中,您可以将数据可视化为 k 维空间中的点云……
— 第 305 页,《数据挖掘:实用机器学习工具和技术》,第 4 版,2016 年。
特征空间中维度数量过多可能意味着该空间的体积非常大,反过来,该空间中的点(数据行)通常代表一个很小且不具代表性的样本。
这会极大地影响在具有许多输入特征的数据上拟合的机器学习算法的性能,通常称为“维度灾难”。
因此,通常需要减少输入特征的数量。这会减少特征空间的维度,因此称为“降维”。
一种流行的降维方法是使用线性代数领域的各种技术。这通常被称为“特征投影”,所使用的算法被称为“投影方法”。
投影方法旨在减少特征空间中的维度数量,同时保留数据中观察到的变量之间最重要的结构或关系。
在处理高维数据时,通过将数据投影到捕获数据“本质”的低维子空间来降低维度通常很有用。这被称为降维。
— 第 11 页,《机器学习:概率视角》,2012 年。
生成的投影数据集可以作为输入来训练机器学习模型。
本质上,原始特征不再存在,而是从可用数据中构建新的特征,这些新特征与原始数据不直接可比,例如,没有列名。
将来在进行预测时,任何输入到模型中的新数据(例如测试数据集和新数据集)也必须使用相同的技术进行投影。
想开始学习数据准备吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
线性判别分析
线性判别分析,简称 LDA,是一种用于多类别分类的线性机器学习算法。
它不应与“潜在狄利克雷分配”(LDA)混淆,后者也是一种用于文本文档的降维技术。
线性判别分析旨在通过类别值最佳地分离(或判别)训练数据集中的样本。具体来说,该模型旨在找到输入变量的线性组合,从而实现类别之间样本(类别质心或均值)的最大分离和每个类别内样本的最小分离。
……找到预测变量的线性组合,使得组间方差相对于组内方差最大化。[…] 找到预测变量的组合,使其在数据中心之间实现最大分离,同时最小化每组数据内的变异。
— 第 289 页,《应用预测建模》,2013 年。
有许多方法可以构建和解决 LDA;例如,通常根据贝叶斯定理和条件概率来描述 LDA 算法。
在实践中,用于多类别分类的 LDA 通常使用线性代数工具实现,并且像 PCA 一样,使用矩阵分解作为该技术的核心。因此,在拟合 LDA 模型之前对数据进行标准化可能是一个好习惯。
有关 LDA 如何详细计算的更多信息,请参阅教程。
现在我们熟悉了降维和 LDA,接下来我们看看如何在 scikit-learn 库中使用这种方法。
LDA Scikit-Learn API
我们可以使用 LDA 计算数据集的投影,并选择投影的维度或分量的数量作为模型的输入。
scikit-learn 库提供了 LinearDiscriminantAnalysis 类,该类可以在数据集上进行拟合,并用于转换训练数据集和将来任何其他数据集。
例如:
1 2 3 4 5 6 7 8 9 |
... # 准备数据集 数据 = ... # 定义转换 lda = LinearDiscriminantAnalysis() # 准备对数据集进行转换 lda.fit(data) # 对数据集应用转换 transformed = lda.transform(data) |
LDA 的输出可以作为训练模型的输入。
也许最好的方法是使用 Pipeline,其中第一步是 LDA 转换,下一步是接受转换数据作为输入的学习算法。
1 2 3 4 |
... # 定义管道 steps = [('lda', LinearDiscriminantAnalysis()), ('m', GaussianNB())] model = Pipeline(steps=steps) |
如果输入变量具有不同的单位或尺度,在执行 LDA 转换之前对数据进行标准化也是一个好主意;例如
1 2 3 4 |
... # 定义管道 steps = [('s', StandardScaler()), ('lda', LinearDiscriminantAnalysis()), ('m', GaussianNB())] model = Pipeline(steps=steps) |
现在我们熟悉了 LDA API,接下来我们看一个工作示例。
LDA 用于降维的实例
首先,我们可以使用 make_classification() 函数来创建一个合成的 10 类分类问题,包含 1,000 个样本和 20 个输入特征,其中 15 个输入是具有意义的。
完整的示例如下所示。
1 2 3 4 5 6 |
# 测试分类数据集 from sklearn.datasets import make_classification # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10) # 汇总数据集 print(X.shape, y.shape) |
运行示例会创建数据集并总结输入和输出组件的形状。
1 |
(1000, 20) (1000,) |
接下来,我们可以使用此数据集上的降维同时拟合朴素贝叶斯模型。
我们将使用一个 Pipeline,其中第一步执行 LDA 转换并选择最重要的五个维度或分量,然后根据这些特征拟合一个 朴素贝叶斯 模型。我们不需要对这个数据集中的变量进行标准化,因为所有变量的尺度都是相同的。
该管道将使用重复分层交叉验证进行评估,其中包含三次重复和每次重复 10 折。性能以平均分类准确度表示。
完整的示例如下所示。
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 from sklearn.naive_bayes import GaussianNB # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10) # 定义管道 steps = [('lda', LinearDiscriminantAnalysis(n_components=5)), ('m', GaussianNB())] 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, error_score='raise') # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例会评估模型并报告分类准确率。
注意:由于算法或评估过程的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
在本例中,我们可以看到 LDA 转换与朴素贝叶斯结合的性能约为 31.4%。
1 |
准确度:0.314 (0.049) |
我们如何知道将 20 个输入维度减少到 5 个是好的还是我们能做到的最好?
我们不知道;5 是一个任意的选择。
一个更好的方法是使用不同数量的输入特征来评估相同的转换和模型,并选择能带来最佳平均性能的特征数量(降维程度)。
LDA 用于降维的组件数量受限于类别数量减一,在本例中是 (10 – 1) 或 9。
下面的示例执行了这个实验,并总结了每个配置的平均分类准确率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# 比较 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 from sklearn.naive_bayes import GaussianNB from matplotlib import pyplot # 获取数据集 定义 获取_数据集(): X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10) 返回 X, y # 获取要评估的模型列表 定义 获取_模型(): models = dict() for i in range(1,10): steps = [('lda', LinearDiscriminantAnalysis(n_components=i)), ('m', GaussianNB())] models[str(i)] = Pipeline(steps=steps) 返回 模型 # 使用交叉验证评估给定模型 def evaluate_model(model, X, y): cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise') 返回 分数 # 定义数据集 X, y = get_dataset() # 获取要评估的模型 模型 = 获取_模型() # 评估模型并存储结果 results, names = list(), list() for name, model in models.items(): scores = evaluate_model(model, X, y) results.append(scores) names.append(name) print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores))) # 绘制模型性能以供比较 pyplot.boxplot(results, labels=names, showmeans=True) pyplot.show() |
运行该示例首先报告每个选定组件或特征数量的分类准确性。
注意:由于算法或评估过程的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
我们可以看到随着维度数量的增加,性能总体呈上升趋势。在此数据集上,结果表明维度数量与模型分类准确性之间存在权衡。
结果表明,使用默认的九个组件在此数据集上实现了最佳性能,尽管在使用的维度较少时存在轻微的权衡。
1 2 3 4 5 6 7 8 9 |
>1 0.182 (0.032) >2 0.235 (0.036) >3 0.267 (0.038) >4 0.303 (0.037) >5 0.314 (0.049) >6 0.314 (0.040) >7 0.329 (0.042) >8 0.343 (0.045) >9 0.358 (0.056) |
为每个配置的维度数量的准确度分数分布创建了一个箱线图。
我们可以看到分类准确性随组件数量增加的趋势,并在九个组件处达到上限。

LDA 组件数量与分类准确度的箱线图
我们可以选择使用 LDA 转换和朴素贝叶斯模型的组合作为我们的最终模型。
这涉及在所有可用数据上拟合 Pipeline,并使用该 Pipeline 对新数据进行预测。重要的是,必须对这些新数据执行相同的转换,这通过 Pipeline 自动处理。
以下代码提供了一个示例,说明如何使用 LDA 转换在新数据上拟合和使用最终模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 使用 LDA 和朴素贝叶斯进行预测 from sklearn.datasets import make_classification from sklearn.pipeline import Pipeline from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.naive_bayes import GaussianNB # 定义数据集 X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10) # 定义模型 steps = [('lda', LinearDiscriminantAnalysis(n_components=9)), ('m', GaussianNB())] model = Pipeline(steps=steps) # 在整个数据集上拟合模型 model.fit(X, y) # 进行单次预测 row = [[2.3548775,-1.69674567,1.6193882,-1.19668862,-2.85422348,-2.00998376,16.56128782,2.57257575,9.93779782,0.43415008,6.08274911,2.12689336,1.70100279,3.32160983,13.02048541,-3.05034488,2.06346747,-3.33390362,2.45147541,-1.23455205]] yhat = model.predict(row) print('Predicted Class: %d' % yhat[0]) |
运行示例会在所有可用数据上拟合管道,并对新数据进行预测。
在这里,转换使用了我们从上述测试中发现的 LDA 转换中最重要的九个组件。
提供了一行包含 20 列的新数据,并将其自动转换为 15 个组件,然后输入到朴素贝叶斯模型中以预测类别标签。
1 |
预测类别:6 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
书籍
- 机器学习:概率视角, 2012.
- 《数据挖掘:实用机器学习工具和技术》,第 4 版,2016 年。
- 模式识别与机器学习, 2006.
- 应用预测建模, 2013.
API
- 将信号分解为组件(矩阵分解问题),scikit-learn.
- sklearn.discriminant_analysis.LinearDiscriminantAnalysis API.
- sklearn.pipeline.Pipeline API.
文章
总结
在本教程中,您学习了如何在开发预测模型时使用 LDA 进行降维。
具体来说,你学到了:
- 降维涉及减少建模数据中的输入变量或列的数量。
- LDA 是一种多类别分类技术,可用于自动执行降维。
- 如何评估使用 LDA 投影作为输入并使用新的原始数据进行预测的预测模型。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
我想知道在 LDA/FDA 降维的背景下。(不是用于预测)
输出是“c-1”,其中“c”是类别的数量,数据的维度是 n,且“n>c”。
假设我的原始数据集有 2 个类别,输出将是 1 维(2 – 1 = 1),同样,如果我的原始数据集有 5 个类别,输出将是 4 维。
输出是您选择配置 LDA 以产生的内容——正如我们在上述教程中看到的那样。
尊敬的Jason博士,
在上述代码中
我的问题是关于
如果 n_components = 5,LDA 是选择 make_classification 生成的前 5 个特征,还是 LDA 根据投影算法“自动”选择 5 个特征。
我们如何识别 LDA 使用了 make_classification 生成的 20 个特征中的哪些特征?
谢谢你,
悉尼的Anthony
我相信 LDA 选择的特征数量必须小于类别的数量。
这与其他方法有很大的不同。
不,LDA 正在创建投影,就像 PCA 和 SVD 一样,例如,它是一种“降维”方法。而不是“特征选择”方法。
区别
https://machinelearning.org.cn/faq/single-faq/what-is-the-difference-between-dimensionality-reduction-and-feature-selection
尊敬的Jason博士,
谢谢你的指点。
LDA 正在创建一个投影,这被视为一种“降维”方法,而不是特征选择方法。
根据 https://machinelearning.org.cn/principal-components-analysis-for-dimensionality-reduction-in-python/,“...更少的输入变量可以生成一个更简单的预测模型,该模型在对新数据进行预测时可能具有更好的性能...”
这仍然引发了以下问题:
* 要通过使用更少的输入变量 = 更少的输入特征来获得更简单的预测模型,您在更简单的模型中包含哪些更少的输入变量 = 更少的输入特征?
* 例如,如果您的数据有 10 个特征,并且 LDA 说您需要 5 个特征来解释 y 的大部分变异,您是否不需要执行 10C5 = 252 个模型?
* 这是否意味着除了 LDA 之外,您还需要一种特征选择技术来选择 5 个特征?
请注意这些词——除了 LDA 之外,您还需要一种特征选择技术,从 10 个特征中选择 5 个特征。
再次感谢您的时间,
悉尼的Anthony
LDA 可以用作预测模型。
LDA 也可以用作降维方法,其输出可以输入到您喜欢的任何模型中。
本教程只关注后者。
尊敬的Jason博士,
我从 LDA 和 PCA 教程中了解到,您可以了解需要多少个组件才能获得一个简洁的模型。在 PCA 教程中,一系列箱线图显示可以使用 15 个组件。
但这适用于 15 个投影组件,而不是 15 个特征。
那么,拥有 15 个投影组件如何帮助我降低维度,以及如何帮助我确定使用了哪些原始未投影特征?
谢谢你,
悉尼的Anthony
尊敬的Jason博士,
我想我“恍然大悟”了。
但我仍然想问两个问题。
我是这样理解的。
如果我们去看 https://machinelearning.org.cn/linear-discriminant-analysis-for-dimensionality-reduction-in-python/ 上的教程,并查看代码的第 10 到 16 行。
教训
* 使用 LDA,您不是在寻找减少特征的方法。相反,您保留所有特征,但使用最有用的投影组件(恰好是 15 个组件)进行预测。
* 您仍然使用所有特征进行预测——但您只使用 LDA 算法的 15 个投影组件,基于所有 20 个特征进行预测。
例如,我们正在使用所有 20 个特征作为输入,由 LDA 的 15 个组件处理后进行预测。
预测类别是基于 15 个投影组件。
请问:
* LDA 算法是如何确定需要 15 个投影组件的。
* 如果在建模中我们希望减少输入特征的数量以避免过拟合。为什么在上述示例中,当您想要使用更少的特征进行预测时,我们却使用了所有 20 个特征进行预测?
谢谢,我希望这次我理解对了,
悉尼的Anthony
正确。但是,它不是选择特征,而是一种投影(较低维度的新特征)。
该方法已在上面和进一步阅读部分中描述。
LDA 必须用于将数据转换到较低维度空间,然后才能在模型中使用。
降维方法用作数据的转换,其结果被输入到模型中——这意味着您使用更少的特征进行建模。
尊敬的Jason博士,
谢谢你的回复。
从您推荐的阅读材料 https://machinelearning.org.cn/linear-discriminant-analysis-for-machine-learning/ 中,我理解了这一点。
* LDA 通过贝叶斯定理估计新输入集属于每个类别的条件概率来进行预测。获得最高概率的类别是输出类别,并进行预测。关键词 LDA 基于概率进行预测。
请问:
*是的,您可以使用 X 的所有变量进行预测。
*但是,当目标是使用 X 的子集时,使用所有 X 来预测 y 有什么意义呢?
例如,您使用了 X 的所有 20 个特征来预测 y。
# 这里您正在从 X 的所有特征预测 y——目标不应该是使用 X 的子集获得一个简洁的模型吗?
行 = [[2.3548775,-1.69674567,1.6193882,-1.19668862,-2.85422348,-2.00998376,16.56128782,2.57257575,9.93779782,0.43415008,6.08274911,2.12689336,1.70100279,3.32160983,13.02048541,-3.05034488,2.06346747,-3.33390362,2.45147541,-1.23455205]]
yhat = model.predict(row)
* 换句话说,投影方法需要 X 的所有特征来预测 y。
* “为什么要关心”使用 LDA 和 PCA 等投影技术,它们使用 X 的所有特征,而特征选择技术则不然?
* 因此,诸如 SelectKBest 和 RFE 等特征约简技术比 PCA 和 LDA 等投影技术更现代,因为特征约简技术能够使用 X 中更少的变量(而不是所有变量)充分预测模型?
谢谢你,
悉尼的Anthony
有两种独立的用例。
LDA 模型可以像任何其他机器学习模型一样使用所有原始输入。它也可以用于降维。本教程仅关注后者。
不,特征选择和降维都将原始数据转换为变量较少的形式,然后可以将其输入到模型中。这两种情况的优点是模型在较少的输入变量上运行。
尊敬的Jason博士,
再次感谢您的回复,不胜感激。
关于您回复的第二段,这些较少的变量是模型中使用的投影变量,然后这些变量用于确定模型的输出 y。
因此,决定 y 值是基于概率的,因为可以使用 LDA 的 predict_proba 方法中的预测概率函数。
谢谢你,
悉尼的Anthony
由于 LDA 是一种监督方法,需要标签才能在转换后的特征空间中实现类别分离。您提到原始特征不再存在,而是构建了新的特征,这些特征不能直接与原始数据进行比较。但是这些新特征难道没有看到正确的标签吗?因此,从本质上讲,使用 LDA 模型在 LDA 模型中测试数据是否会过拟合?
虽然这可能/可能不明显,但您也提到,将来在进行预测时,任何输入到模型中的新数据(例如测试数据集和新数据集)也必须使用相同的技术进行投影。由于 LDA 需要标签,您如何在不知道标签的情况下预测新的未见过/未标记的测试数据?
我之所以这样问,是因为我正在做一个项目,我使用了 LDA,并获得了一些很好的类别分离和巨大的降维。然后,我在转换后的特征空间上使用逻辑回归并执行了交叉验证。我每次折叠都获得了近 100% 的准确率,我怀疑这是否是因为 LDA 模型已经对其分类的数据进行了训练。此外,我不知道如何在不知道标签的情况下对未见过的数据进行预测。
很好的问题!
也许,但通常情况下:不会。您可以使用相同的论点来反驳任何在已知标签数据上训练的模型。
创建投影的方法是从训练数据中学习的。
做得好!确保您避免了数据泄漏。将结果与原始数据上的逻辑回归进行比较,也许不需要投影/预测问题很简单/微不足道(这是好事!)。