线性判别分析是一种线性分类机器学习算法。
该算法涉及根据每个输入变量的观测值的特定分布,为每个类开发一个概率模型。然后,通过计算新示例属于每个类的条件概率并选择概率最高的类来对新示例进行分类。
因此,它是一种相对简单的概率分类模型,对每个输入变量的分布做出严格的假设,尽管即使这些预期被违反,它也能做出有效的预测(例如,它能优雅地失败)。
在本教程中,您将使用 Python 了解线性判别分析分类机器学习算法。
完成本教程后,您将了解:
- 线性判别分析是一种简单的线性机器学习分类算法。
- 如何使用 Scikit-Learn 拟合、评估和预测线性判别分析模型。
- 如何在给定数据集上调整线性判别分析算法的超参数。
让我们开始吧。

使用 Python 进行线性判别分析
照片作者:Mihai Lucîț,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 线性判别分析
- 使用 scikit-learn 进行线性判别分析
- 调整 LDA 超参数
线性判别分析
线性判别分析,简称 LDA,是一种分类机器学习算法。
它通过计算类标签的输入特征的汇总统计信息(例如均值和标准差)来工作。这些统计信息代表了从训练数据中学习到的模型。在实践中,线性代数运算用于通过矩阵分解有效地计算所需量。
通过根据每个输入特征的值估计新示例属于每个类标签的概率来进行预测。然后将导致最大概率的类分配给该示例。因此,LDA 可被视为应用贝叶斯定理进行分类的一个简单应用。
LDA 假设输入变量是数值型且呈正态分布,并且它们具有相同的方差(分布范围)。如果情况并非如此,则可能需要转换数据以使其具有高斯分布,并在建模前对数据进行标准化或归一化。
… LDA 分类器源于假设每个类中的观测值来自具有类特定均值向量和共同方差的正态分布
— 第 142 页,《统计学习导论:应用 R》,2014。
它还假设输入变量不相关;如果相关,PCA 变换可能有助于消除线性依赖。
… 从业人员在使用 LDA 之前应特别严格地预处理数据。我们建议对预测变量进行中心化和缩放,并删除接近零方差的预测变量。
— 第 293 页,《应用预测建模》,2013。
尽管如此,即使违反这些预期,该模型也能表现良好。
LDA 模型天然是多类的。这意味着它支持二分类问题,并且无需修改或增强即可扩展到三个或更多类别(多类分类)。
它是一种线性分类算法,如逻辑回归。这意味着在特征空间中,类是通过直线或超平面分隔的。该方法可以进行扩展,允许其他形状,例如二次判别分析 (QDA),它允许决策边界具有弯曲形状。
… 与 LDA 不同,QDA 假设每个类都有自己的协方差矩阵。
— 第 149 页,《统计学习导论:应用 R》,2014。
现在我们熟悉了 LDA,让我们看看如何使用 scikit-learn 库拟合和评估模型。
使用 scikit-learn 进行线性判别分析
线性判别分析可以通过 LinearDiscriminantAnalysis 类在 scikit-learn Python 机器学习库中使用。
该方法可以直接使用,无需配置,尽管该实现确实提供了用于自定义的参数,例如求解器的选择和惩罚的使用。
1 2 3 |
... # 创建 lda 模型 model = LinearDiscriminantAnalysis() |
我们可以通过一个实际示例来演示线性判别分析方法。
首先,让我们定义一个合成分类数据集。
我们将使用 make_classification() 函数创建一个包含 1000 个示例的数据集,每个示例有 10 个输入变量。
该示例创建并总结了数据集。
1 2 3 4 5 6 |
# 测试分类数据集 from sklearn.datasets import make_classification # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=10, n_redundant=0, random_state=1) # 汇总数据集 print(X.shape, y.shape) |
运行示例创建数据集并确认数据集的行数和列数。
1 |
(1000, 10) (1000,) |
我们可以使用 重复分层 K 折交叉验证通过 RepeatedStratifiedKFold 类来拟合和评估线性判别分析模型。我们将在测试框架中使用 10 折和 3 次重复。
下面列出了针对合成二分类任务评估线性判别分析模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 评估数据集上的 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.discriminant_analysis import LinearDiscriminantAnalysis # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=10, n_redundant=0, random_state=1) # 定义模型 model = LinearDiscriminantAnalysis() # 定义模型评估方法 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) # 总结结果 print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行示例将在合成数据集上评估线性判别分析算法,并报告三次重复的 10 折交叉验证的平均准确率。
鉴于学习算法的随机性,您的具体结果可能会有所不同。可以尝试运行几次示例。
在这种情况下,我们可以看到该模型实现了大约 89.3% 的平均准确率。
1 |
平均准确率:0.893 (0.033) |
我们可以选择使用线性判别分析作为我们的最终模型,并在新数据上进行预测。
这可以通过在所有可用数据上拟合模型并通过传递新数据行来调用 predict() 函数来实现。
我们可以在下面列出的完整示例中演示这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 在数据集上使用 lda 模型进行预测 from sklearn.datasets import make_classification from sklearn.discriminant_analysis import LinearDiscriminantAnalysis # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=10, n_redundant=0, random_state=1) # 定义模型 model = LinearDiscriminantAnalysis() # 拟合模型 model.fit(X, y) # 定义新数据 row = [0.12777556,-3.64400522,-2.23268854,-1.82114386,1.75466361,0.1243966,1.03397657,2.35822076,1.01001752,0.56768485] # 进行预测 yhat = model.predict([row]) # 总结预测 print('Predicted Class: %d' % yhat) |
运行示例后,模型将被拟合,并对新数据行进行类别标签预测。
1 |
预测类别:1 |
接下来,我们可以看看如何配置模型超参数。
调整 LDA 超参数
必须为特定数据集配置线性判别分析方法的超参数。
一个重要的超参数是求解器,它默认为“svd”,但也可以设置为支持收缩能力的其他求解器值。
下面的示例使用 GridSearchCV 类和不同的求解器值网格来演示这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 网格搜索 lda 的求解器 from sklearn.datasets import make_classification from sklearn.model_selection import GridSearchCV from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.discriminant_analysis import LinearDiscriminantAnalysis # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=10, n_redundant=0, random_state=1) # 定义模型 model = LinearDiscriminantAnalysis() # 定义模型评估方法 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义网格 grid = dict() grid['solver'] = ['svd', 'lsqr', 'eigen'] # 定义搜索 search = GridSearchCV(model, grid, scoring='accuracy', cv=cv, n_jobs=-1) # 执行搜索 results = search.fit(X, y) # 总结 print('Mean Accuracy: %.3f' % results.best_score_) print('Config: %s' % results.best_params_) |
运行示例将使用重复交叉验证评估每种配置组合。
鉴于学习算法的随机性,您的具体结果可能会有所不同。尝试运行几次示例。
在这种情况下,我们可以看到默认的 SVD 求解器比其他内置求解器表现更好。
1 2 |
平均准确率:0.893 配置:{'solver': 'svd'} |
接下来,我们可以探讨使用收缩功能与模型是否能提高性能。
收缩为模型添加了一个惩罚,该惩罚充当一种正则化器,降低了模型的复杂性。
正则化以增加偏差为代价,减少与样本估计相关的方差。这种偏差-方差权衡通常由一个或多个(置信度)参数来控制,这些参数控制对“合理”的(总体)参数值集合的偏倚强度。
— 《正则化判别分析》,1989。
这可以通过“shrinkage”参数进行设置,其值可以在 0 到 1 之间。我们将以 0.01 的间隔测试网格上的值。
为了使用惩罚,必须选择一个支持此功能的求解器,例如 'eigen' 或 'lsqr'。在这里,我们将使用后者。
下面列出了调整收缩超参数的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 网格搜索 lda 的收缩 from numpy import arange from sklearn.datasets import make_classification from sklearn.model_selection import GridSearchCV from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.discriminant_analysis import LinearDiscriminantAnalysis # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=10, n_redundant=0, random_state=1) # 定义模型 model = LinearDiscriminantAnalysis(solver='lsqr') # 定义模型评估方法 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义网格 grid = dict() grid['shrinkage'] = arange(0, 1, 0.01) # 定义搜索 search = GridSearchCV(model, grid, scoring='accuracy', cv=cv, n_jobs=-1) # 执行搜索 results = search.fit(X, y) # 总结 print('Mean Accuracy: %.3f' % results.best_score_) print('Config: %s' % results.best_params_) |
运行示例将使用重复交叉验证评估每种配置组合。
鉴于学习算法的随机性,您的具体结果可能会有所不同。尝试运行几次示例。
在这种情况下,我们可以看到使用收缩功能将性能从约 89.3% 略微提高到约 89.4%,值为 0.02。
1 2 |
平均准确率:0.894 配置:{'shrinkage': 0.02} |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
论文
- 正则化判别分析, 1989.
书籍
- 应用预测建模, 2013.
- 统计学习导论:R语言应用, 2014.
API
文章
总结
在本教程中,您使用 Python 了解了线性判别分析分类机器学习算法。
具体来说,你学到了:
- 线性判别分析是一种简单的线性机器学习分类算法。
- 如何使用 Scikit-Learn 拟合、评估和预测线性判别分析模型。
- 如何在给定数据集上调整线性判别分析算法的超参数。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
非常有教育意义的文章,感谢分享。
谢谢!
尊敬的Jason博士,
这是一个让 gridsearch 的例子
结果
* 将更多参数添加到网格搜索中并未提高准确率。
* 最佳求解器是“lsqr”。与 Jason 博士的答案相比,最佳求解器是“svd”。
* 排除“lsqr”并将求解器“svd”和“eigen”保留在其中,“eigen”是最佳求解器,但结果与平均准确率 0.894 相同。
* 收缩和“svd”不能作为网格搜索参数“混合”。
谢谢你,
悉尼的Anthony
干得好!
非常有帮助!
谢谢。
不错的教程。您能做一个类似的关于判别相关分析的教程吗?
Jason 博士您好 – 感谢您关于使用 scikit-learn 进行线性判别分析的精彩教程。我的问题是 scikit-learn 使用哪种协方差:它计算“合并方差”,将每个特征从总平均值(所有特征的平均值)中减去,还是实际上计算每个类的协方差,即在计算单独的协方差时,将特征从每个类的特征平均值中减去……然后将单独的协方差按先验概率加权组合成一个单一的协方差?谢谢!
你好 Harold……不客气!以下资源可能对您有帮助
https://scikit-learn.cn/stable/modules/covariance.html
嗨 James,
是的,感谢您提供关于 scikit-learn 协方差的链接,我很感激。我的具体问题是 scikit-learn 的线性判别算法使用哪种协方差计算或估计?谢谢!