递归特征消除 (Recursive Feature Elimination),简称 RFE,是一种流行的特征选择算法。
RFE 广受欢迎,因为它易于配置和使用,并且在从训练数据集中选择与预测目标变量最相关或更相关的特征(列)方面非常有效。
使用 RFE 时有两个重要的配置选项:要选择的特征数量和用于辅助选择特征的算法。这两个超参数都可以进行探索,尽管该方法的性能并不强烈依赖于这些超参数的良好配置。
在本教程中,您将学习如何在 Python 中使用递归特征消除 (RFE) 进行特征选择。
完成本教程后,您将了解:
- RFE 是一种从训练数据集中消除特征以进行特征选择的有效方法。
- 如何将 RFE 用于分类和回归预测建模问题的特征选择。
- 如何探索 RFE 过程选择的特征数量和使用的封装算法。
使用我的新书 《机器学习的数据准备》 启动您的项目,其中包括逐步教程和所有示例的 Python 源代码文件。
让我们开始吧。

Python 中的递归特征消除 (RFE) 用于特征选择
由 djandywdotcom 拍摄,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 递归特征消除
- 使用 scikit-learn 进行 RFE
- 用于分类的 RFE
- 用于回归的 RFE
- RFE 超参数
- 探索特征数量
- 自动选择特征数量
- 选择了哪些特征
- 探索基本算法
递归特征消除
递归特征消除 (RFE) 是一种特征选择算法。
用于分类或回归的机器学习数据集由行和列组成,就像 Excel 电子表格一样。行通常称为样本,列称为特征,例如问题域中观测的特征。
特征选择是指选择数据集中最相关特征(列)子集的技术。更少的特征可以使机器学习算法运行更高效(更少的空间或时间复杂度)并更有效。一些机器学习算法可能会被不相关的输入特征误导,导致预测性能下降。
有关特征选择的更多信息,请参阅教程
RFE 是一种封装式特征选择算法。这意味着在方法的核心中提供并使用不同的机器学习算法,该算法由 RFE 封装,并用于辅助选择特征。这与基于过滤器的特征选择形成对比,后者对每个特征进行评分并选择得分最大(或最小)的特征。
从技术上讲,RFE 是一种封装式特征选择算法,它还在内部使用基于过滤器的特征选择。
RFE 通过从训练数据集中的所有特征开始,并成功移除特征直到剩下所需数量的特征来搜索特征子集。
这是通过拟合模型核心中使用的给定机器学习算法、按重要性对特征进行排名、丢弃最不重要的特征以及重新拟合模型来实现的。这个过程重复进行,直到剩下指定数量的特征。
当创建完整的模型时,会计算变量重要性度量,该度量将预测因子从最重要到最不重要进行排名。[...] 在搜索的每个阶段,最不重要的预测因子在重建模型之前被迭代消除。
— 第 494-495 页,《应用预测建模》,2013 年。
特征要么使用提供的机器学习模型(例如,决策树等一些算法提供重要性分数)进行评分,要么使用统计方法进行评分。
重要性计算可以是基于模型的(例如,随机森林重要性标准),也可以是独立于完整模型的更通用方法。
— 第 494 页,《应用预测建模》,2013 年。
现在我们熟悉了 RFE 过程,让我们回顾一下如何在我们的项目中使用它。
想开始学习数据准备吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
使用 scikit-learn 进行 RFE
RFE 可以从头开始实现,尽管对于初学者来说可能具有挑战性。
scikit-learn Python 机器学习库为机器学习提供了 RFE 的实现。
它在库的现代版本中可用。
首先,通过运行以下脚本确认您正在使用该库的现代版本
1 2 3 |
# 检查 scikit-learn 版本 import sklearn print(sklearn.__version__) |
运行脚本将打印您的 scikit-learn 版本。
您的版本应该相同或更高。如果不是,您必须升级您的 scikit-learn 库版本。
1 |
0.22.1 |
RFE 方法可通过 scikit-learn 中的 RFE 类获得。
RFE 是一个转换器。要使用它,首先通过“estimator”参数指定选择的算法,并通过“n_features_to_select”参数指定要选择的特征数量来配置该类。
该算法必须提供一种计算重要性分数的方法,例如决策树。RFE 中使用的算法不必是在选定特征上拟合的算法;可以使用不同的算法。
配置完成后,必须在训练数据集上拟合该类以通过调用 fit() 函数选择特征。拟合该类后,可以通过“support_”属性查看输入变量的选择,该属性为每个输入变量提供 True 或 False。
然后可以通过调用 transform() 函数将其应用于训练和测试数据集。
1 2 3 4 5 6 7 |
... # 定义方法 rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=3) # 拟合模型 rfe.fit(X, y) # 转换数据 X, y = rfe.transform(X, y) |
通常使用 k 折交叉验证来评估数据集上的机器学习算法。在使用交叉验证时,最好将 RFE 等数据转换作为 Pipeline 的一部分执行,以避免数据泄露。
现在我们熟悉了 RFE API,让我们看看如何为分类和回归开发 RFE。
用于分类的 RFE
在本节中,我们将介绍如何将 RFE 用于分类问题。
首先,我们可以使用 make_classification() 函数创建一个合成二元分类问题,其中包含 1,000 个示例和 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=5, n_redundant=5, random_state=1) # 汇总数据集 print(X.shape, y.shape) |
运行示例会创建数据集并总结输入和输出组件的形状。
1 |
(1000, 10) (1000,) |
接下来,我们可以在此数据集上评估 RFE 特征选择算法。我们将使用 DecisionTreeClassifier 来选择特征,并将特征数量设置为五。然后,我们将在选定的特征上拟合一个新的 DecisionTreeClassifier 模型。
我们将使用重复分层 k 折交叉验证来评估模型,其中重复 3 次,折叠 10 次。我们将报告模型在所有重复和折叠中的平均准确度和标准差。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 评估用于分类的 RFE 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.特征选择 导入 RFE from sklearn.tree import DecisionTreeClassifier from sklearn.pipeline import Pipeline # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1) # 创建管道 rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=5) model = DecisionTreeClassifier() pipeline = Pipeline(steps=[('s',rfe),('m',model)]) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise') # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例报告了模型的平均准确度和标准差。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。请尝试多次运行示例并比较平均结果。
在这种情况下,我们可以看到使用决策树并选择五个特征,然后根据选定特征拟合决策树的 RFE 实现了大约 88.6% 的分类准确率。
1 |
准确率:0.886 (0.030) |
我们还可以将 RFE 模型管道作为最终模型并进行分类预测。
首先,RFE 和模型在所有可用数据上进行拟合,然后可以调用 predict() 函数对新数据进行预测。
以下示例在我们的二元分类数据集上演示了这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用 RFE 管道进行预测 from numpy import mean from numpy import std from sklearn.datasets import make_classification 从 sklearn.特征选择 导入 RFE from sklearn.tree import DecisionTreeClassifier from sklearn.pipeline import Pipeline # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1) # 创建管道 rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=5) model = DecisionTreeClassifier() pipeline = Pipeline(steps=[('s',rfe),('m',model)]) # 在所有可用数据上拟合模型 pipeline.fit(X, y) # 对一个示例进行预测 data = [[2.56999479,-0.13019997,3.16075093,-4.35936352,-1.61271951,-1.39352057,-2.48924933,-1.93094078,3.26130366,2.05692145]] yhat = pipeline.predict(data) print('Predicted Class: %d' % (yhat)) |
运行该示例将 RFE 管道拟合到整个数据集,然后用于对一行新数据进行预测,就像我们在应用程序中使用模型时一样。
1 |
预测类别:1 |
现在我们熟悉了将 RFE 用于分类,让我们看看回归的 API。
用于回归的 RFE
在本节中,我们将介绍如何将 RFE 用于回归问题。
首先,我们可以使用 make_regression() 函数创建一个合成回归问题,其中包含 1,000 个示例和 10 个输入特征,其中五个是重要的,五个是冗余的。
完整的示例如下所示。
1 2 3 4 5 6 |
# 测试回归数据集 from sklearn.datasets import make_regression # 定义数据集 X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1) # 汇总数据集 print(X.shape, y.shape) |
运行示例会创建数据集并总结输入和输出组件的形状。
1 |
(1000, 10) (1000,) |
接下来,我们可以在此数据集上评估 REFE 算法。
与上一节一样,我们将使用重复 k 折交叉验证评估使用决策树的管道,重复三次,折数为 10。
我们将报告模型在所有重复和折叠中的平均绝对误差 (MAE)。scikit-learn 库将 MAE 转换为负数,使其最大化而不是最小化。这意味着负 MAE 越大越好,完美模型的 MAE 为 0。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 评估用于回归的 RFE from numpy import mean from numpy import std from sklearn.datasets import make_regression from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedKFold 从 sklearn.特征选择 导入 RFE 来自 sklearn.tree 导入 DecisionTreeRegressor from sklearn.pipeline import Pipeline # 定义数据集 X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1) # 创建管道 rfe = RFE(estimator=DecisionTreeRegressor(), n_features_to_select=5) 模型 = DecisionTreeRegressor() pipeline = Pipeline(steps=[('s',rfe),('m',model)]) # 评估模型 cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(pipeline, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise') # 报告表现 print('MAE: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例报告了模型的平均准确度和标准差。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。请尝试多次运行示例并比较平均结果。
在这种情况下,我们可以看到使用决策树模型的 RFE 管道实现了大约 26 的 MAE。
1 |
MAE: -26.853 (2.696) |
我们还可以将 c 作为最终模型并进行回归预测。
首先,管道在所有可用数据上进行拟合,然后可以调用 predict() 函数对新数据进行预测。
以下示例在我们的回归数据集上演示了这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 使用 RFE 管道进行回归预测 from numpy import mean from numpy import std from sklearn.datasets import make_regression 从 sklearn.特征选择 导入 RFE 来自 sklearn.tree 导入 DecisionTreeRegressor from sklearn.pipeline import Pipeline # 定义数据集 X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1) # 创建管道 rfe = RFE(estimator=DecisionTreeRegressor(), n_features_to_select=5) 模型 = DecisionTreeRegressor() pipeline = Pipeline(steps=[('s',rfe),('m',model)]) # 在所有可用数据上拟合模型 pipeline.fit(X, y) # 对一个示例进行预测 data = [[-2.02220122,0.31563495,0.82797464,-0.30620401,0.16003707,-1.44411381,0.87616892,-0.50446586,0.23009474,0.76201118]] yhat = pipeline.predict(data) print('Predicted: %.3f' % (yhat)) |
运行该示例将 RFE 管道拟合到整个数据集,然后用于对一行新数据进行预测,就像我们在应用程序中使用模型时一样。
1 |
预测值:-84.288 |
现在我们熟悉了如何使用 scikit-learn API 评估和使用 RFE 进行特征选择,让我们看看如何配置模型。
RFE 超参数
在本节中,我们将仔细研究一些您应该考虑为 RFE 特征选择方法调整的超参数及其对模型性能的影响。
探索特征数量
RFE 算法的一个重要超参数是要选择的特征数量。
在上一节中,我们使用了任意数量的选定特征,即五个,这与合成数据集中信息性特征的数量相匹配。实际上,我们无法知道使用 RFE 选择特征的最佳数量;相反,最好测试不同的值。
以下示例演示了在合成二元分类数据集上选择 2 到 10 个不同数量的特征。
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 45 |
# 探索 RFE 的选定特征数量 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.特征选择 导入 RFE from sklearn.tree import DecisionTreeClassifier from sklearn.pipeline import Pipeline from matplotlib import pyplot # 获取数据集 定义 获取_数据集(): X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1) 返回 X, y # 获取要评估的模型列表 定义 获取_模型(): models = dict() for i in range(2, 10): rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=i) model = DecisionTreeClassifier() models[str(i)] = Pipeline(steps=[('s',rfe),('m',model)]) 返回 模型 # 使用交叉验证评估给定模型 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() |
运行示例首先报告每个配置的输入特征数量的平均准确率。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。请尝试多次运行示例并比较平均结果。
在这种情况下,我们可以看到性能随着特征数量的增加而提高,并且正如我们预期的那样,在大约 4 到 7 个特征时达到峰值,因为只有五个特征与目标变量相关。
1 2 3 4 5 6 7 8 |
>2 0.715 (0.044) >3 0.825 (0.031) >4 0.876 (0.033) >5 0.887 (0.030) >6 0.890 (0.031) >7 0.888 (0.025) >8 0.885 (0.028) >9 0.884 (0.025) |
为每个配置的特征数量创建了准确率得分分布的箱线图。

RFE 选定特征数量与分类准确率的箱线图
自动选择特征数量
也可以自动选择 RFE 选择的特征数量。
这可以通过对不同数量的特征进行交叉验证评估来实现,就像我们在上一节中所做的那样,并自动选择导致最佳平均分数的特征数量。
的 RFECV 类为我们实现了这一点。
“RFECV” 的配置与 “RFE” 类在选择所封装算法方面相同。此外,可以通过 “min_features_to_select” 参数(默认为 1)指定要考虑的最小特征数量,我们还可以通过 “cv”(默认为 5)和 “scoring” 参数(分类使用准确率)指定要使用的交叉验证和评分类型。
1 2 3 |
... # 自动选择特征数量 rfe = RFECV(estimator=DecisionTreeClassifier()) |
我们可以在我们的合成二分类问题上演示这一点,并在管道中使用 RFECV 而不是 RFE 来自动选择特征数量。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 自动为 RFE 选择特征数量 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.feature_selection import RFECV from sklearn.tree import DecisionTreeClassifier from sklearn.pipeline import Pipeline # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1) # 创建管道 rfe = RFECV(estimator=DecisionTreeClassifier()) model = DecisionTreeClassifier() pipeline = Pipeline(steps=[('s',rfe),('m',model)]) # 评估模型 cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1) n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise') # 报告表现 print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores))) |
运行示例报告了模型的平均准确度和标准差。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。请尝试多次运行示例并比较平均结果。
在这种情况下,我们可以看到使用决策树的 RFE 自动选择了一定数量的特征,然后在选定的特征上拟合一个决策树,实现了约 88.6% 的分类准确率。
1 |
准确率:0.886 (0.026) |
选择了哪些特征
使用 RFE 时,我们可能想知道哪些特征被选中,哪些被移除。
这可以通过查看拟合的 RFE 对象(或拟合的 RFECV 对象)的属性来实现。“support_” 属性以列索引的顺序报告哪些特征被包含为 True 或 False,而 “ranking_” 属性以相同的顺序报告特征的相对排名。
下面的示例在整个数据集上拟合了一个 RFE 模型,并选择了五个特征,然后报告了每个特征列的索引(0 到 9)、是否被选中(True 或 False),以及相对特征排名。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 报告 RFE 选择了哪些特征 from sklearn.datasets import make_classification 从 sklearn.特征选择 导入 RFE from sklearn.tree import DecisionTreeClassifier # 定义数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1) # 定义 RFE rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=5) # 拟合 RFE rfe.fit(X, y) # 总结所有特征 for i in range(X.shape[1]): print('Column: %d, Selected %s, Rank: %.3f' % (i, rfe.support_[i], rfe.ranking_[i])) |
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。请尝试多次运行示例并比较平均结果。
运行示例列出了 10 个输入特征,以及它们是否被选中,以及它们的相对重要性排名。
1 2 3 4 5 6 7 8 9 10 |
列:0,选中 False,排名:5.000 列:1,选中 False,排名:4.000 列:2,选中 True,排名:1.000 列:3,选中 True,排名:1.000 列:4,选中 True,排名:1.000 列:5,选中 False,排名:6.000 列:6,选中 True,排名:1.000 列:7,选中 False,排名:3.000 列:8,选中 True,排名:1.000 列:9,选中 False,排名:2.000 |
探索基本算法
核心 RFE 中可以使用许多算法,只要它们提供某种变量重要性指示。
大多数决策树算法可能会报告特征重要性中的相同总体趋势,但这并非必然。探索 RFE 封装的不同算法可能会有所帮助。
下面的示例演示了如何探索此配置选项。
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# 探索 RFE 封装的算法 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.特征选择 导入 RFE from sklearn.linear_model import LogisticRegression from sklearn.linear_model import Perceptron from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import GradientBoostingClassifier from sklearn.pipeline import Pipeline from matplotlib import pyplot # 获取数据集 定义 获取_数据集(): X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1) 返回 X, y # 获取要评估的模型列表 定义 获取_模型(): models = dict() # lr rfe = RFE(estimator=LogisticRegression(), n_features_to_select=5) model = DecisionTreeClassifier() models['lr'] = Pipeline(steps=[('s',rfe),('m',model)]) # perceptron rfe = RFE(estimator=Perceptron(), n_features_to_select=5) model = DecisionTreeClassifier() models['per'] = Pipeline(steps=[('s',rfe),('m',model)]) # cart rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=5) model = DecisionTreeClassifier() models['cart'] = Pipeline(steps=[('s',rfe),('m',model)]) # rf rfe = RFE(estimator=RandomForestClassifier(), n_features_to_select=5) model = DecisionTreeClassifier() models['rf'] = Pipeline(steps=[('s',rfe),('m',model)]) # gbm rfe = RFE(estimator=GradientBoostingClassifier(), n_features_to_select=5) model = DecisionTreeClassifier() models['gbm'] = Pipeline(steps=[('s',rfe),('m',model)]) 返回 模型 # 使用交叉验证评估给定模型 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) 返回 分数 # 定义数据集 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 |
>lr 0.893 (0.030) >per 0.843 (0.040) >cart 0.887 (0.033) >rf 0.858 (0.038) >gbm 0.891 (0.030) |
为每个配置的封装算法的准确率分数分布创建了一个箱线图。
我们可以看到逻辑回归、CART 和 GBM 表现良好的总体趋势。这强调了即使在每种情况下用于拟合所选特征的实际模型是相同的,RFE 中使用的模型在选择哪些特征以及进而预测问题的性能方面也会产生重要的影响。

RFE 封装算法与分类准确率的箱线图
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
书籍
- 应用预测建模, 2013.
论文
- 使用支持向量机进行癌症分类的基因选择, 2002.
API
文章
总结
在本教程中,您了解了如何在 Python 中使用递归特征消除 (RFE) 进行特征选择。
具体来说,你学到了:
- RFE 是一种从训练数据集中消除特征以进行特征选择的有效方法。
- 如何将 RFE 用于分类和回归预测建模问题的特征选择。
- 如何探索 RFE 过程选择的特征数量和使用的封装算法。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
嗨,Jason,关于特征选择的精彩教程。这也可以应用于序数数据吗?
我的数据集包含幸福感测量(心理健康、营养质量、睡眠质量等)作为输入特征,这些值可以在 0-10 之间。我想知道其中最有用的特征。我可以使用这种技术还是某种相关性分析?
谢谢!
是的,RFE 与输入数据类型无关。
关于特征选择的非常好的教程。
谢谢!
嗨,Jason,非常感谢 RFE 的教程,我终于明白了。我的问题是:如何查看 RFE 在交叉验证的每个折叠中选择的变量?(在这种情况下,我使用的是 StratifiedCV,只重复 10 折交叉验证)我正在使用您的代码,唯一的区别是,为了选择变量,我使用的是 Ridge,我的模型是 RidgeClassifier。在下面的行中,您可以看到我的代码
rfe = RFE(estimator=Ridge(alpha=1.0000000000000006e-10), n_features_to_select=10)
model=RidgeClassifier(alpha=1.0000000000000006e-10)
Step=[(‘s’,rfe),(‘m’,model)]
pl=Pipeline(steps=Step)
cv=StratifiedKFold(n_splits=10, shuffle=True, random_state=1)
n_scores = round(cross_val_score(pl, X_uo, y_uo, scoring=’accuracy’, cv=cv,n_jobs=-1).mean(),3)
print(‘Stratified Cross validation Accuracy form Ridge model with all the variables: ‘, n_scores)
如果您使用 cross_val_score(),则无法知道,但您可能需要查看 cross_validate(),它允许您阅读更多详细信息。
你好,Jason。你能详细说明以下内容吗?“在使用交叉验证时,最好将 RFE 等数据转换作为管道的一部分进行,以避免数据泄露。”
为什么使用数据转换可以避免数据泄露?
好问题。
如果测试集中的数据在训练期间被模型使用或可用,则称为数据泄露。
https://machinelearning.org.cn/data-leakage-machine-learning/
这可能会给出误导性的结果,通常是乐观的。
解释得很好
感谢您的反馈和支持,abhi!我们非常感谢!
感谢您的文章。您会将交叉验证/模型调优放在哪里?
1. 首先使用所有特征进行交叉验证,然后执行 RFE;
2. 使用 RFE,然后使用选定特征的模型进行交叉验证;
3. 将交叉验证包含在 RFE 中:在 RFE 的每次迭代中,使用当前特征子集调优模型,删除最不重要的特征,再次使用新子集执行交叉验证并丢弃最不重要的特征,依此类推。
哪种方法是正确的?
理想情况下,CV 用于评估整个建模管道。
在管道中,您可能希望使用嵌套的 RFECV 自动配置 RFE。我们称之为嵌套交叉验证。
这个想法与反向选择有什么不同?众所周知,当存在多重共线性时,反向选择、前向选择和逐步选择都不受青睐,而如今随着变量数量的增加,多重共线性更为普遍。
非常相似。
太棒了,非常全面。非常感谢你的努力。
谢谢!
嗨,Jason,非常感谢您的精彩解释。
我想知道,在所有模型都测试完毕后,如何获取选定的特征。我的意思是,在我选择了获胜模型后,如何获取获胜特征?
在模型拟合数据后,您可以访问 RFE 对象并报告选定的特征。
请参阅“哪些特征被选中”部分。
嗨,Jason,
很棒的教程。
您能帮我理解为什么“哪些特征被选中”中选中的列(2,3,4,6,8)与之前 RFE 探索的特征数量(其中重要列为 4-7)不同吗?
谢谢,
RFE 认为不重要的特征实际上可能对模型技能有贡献。
是否有可能从任何成功的预测模型(如传统回归模型)中提取最终的回归公式或方程?非常感谢。
也许从一个简单的线性回归模型中可以,例如,您可以从拟合模型中检索系数。
https://scikit-learn.cn/stable/modules/generated/sklearn.linear_model.LinearRegression.html
有没有关于具有许多输入变量的非线性曲线估计的可靠教程?
抱歉,我目前没有关于这个主题的教程,希望将来会有。
嗨,Jason,
很棒的帖子。在“Scikit-learn 中的 RFE”部分,您解释说 RFE 可以通过“rfe.fit(X,y)”和“rfe.transform(X,y)”方法与 fit 和 transform 方法一起使用。难道不是只有“rfe.transform(X)”没有类标签吗?谢谢!
不,它既是输入也是输出,因此可以评估特征子集。
另请参阅此
https://scikit-learn.cn/stable/modules/generated/sklearn.feature_selection.RFE.html#sklearn.feature_selection.RFE.fit
尊敬的Jason博士,
我尝试将上述方法应用于鸢尾花数据,分别使用 Pipeline 和不使用 Pipeline。
使用 Pipeline
这是不使用管道的鸢尾花数据应用
从结果来看,使用 Pipeline 和不使用 Pipeline 之间的差异很小。
当 n_scores 的均值和标准差之间差异很小的时候,实现 Pipeline 的意义何在?
谢谢你,
悉尼的Anthony
尊敬的Jason博士,
抱歉,我使用了 mean(std)。我应该使用 mean(n_score) 和 std(n_score)
同样的问题——管道的意义何在,它对分数结果的影响微乎其微?
谢谢你,
悉尼的Anthony
我们使用管道是为了避免数据泄露。
https://machinelearning.org.cn/data-preparation-without-data-leakage/
尊敬的Jason博士,
感谢您将我引荐到关于“无数据泄露的数据准备”的文章。
通常这与数据准备方式有关。在上述“实验”中,相关标题分别是“使用朴素数据准备的交叉验证评估”和“使用正确数据准备的交叉验证评估”。
我理解管道方法是将操作放入列表中。
“朴素”和“正确”数据准备方法中的两行代码分别是
是的,分数的均值和标准差结果略有不同。
请原谅我对计算中“泄露”的概念。我以为“泄露”是指 C 或 Java 中的垃圾回收。显然,在数据准备教程中并非如此。
请问
当您将一个变量赋值给另一个变量时,测试数据和训练数据如何相互泄露?您不会期望当您将 X_test 和 y_test 赋值给 k-fold 操作时,它们会与 X_train 和 y_train 混合。
换句话说:虽然管道与线程不同,但如果您不按特定顺序将一组程序进行漏斗处理,您将无法获得准确的答案,就像如果您没有线程执行特定代码块,您将无法获得准确的答案一样?
谢谢你,
悉尼的Anthony
这与线程或编程无关。
相反,它与模型使用了它不应该访问的数据有关。例如,在训练模型时访问来自测试集的“信息”。也许可以重新阅读有关数据泄露的教程。
尊敬的Jason博士,
谢谢您的回复。我已重新阅读,但仍有“思维”障碍。
将其分为背景和问题。
背景知识
管道与“……模型使用了它不应该访问的数据……”有关。
引自博客。
“……对保留测试集的了解泄露到用于训练模型的数据集中……”
“……有关保留数据集(例如测试或验证数据集)的信息可在训练数据集中供模型使用……”
“……这可能发生在测试数据泄露到训练集时,……”
如果我将数据拆分为训练集和测试集,那么在我拆分数据后,信息如何从训练集泄露到测试集或从测试集泄露到训练集。
然后,一旦我将数据拆分为训练集和测试集,测试或训练数据如何泄露回去?
此外,当我进行模型拟合时,
我正在拟合 X_train 和 y_train。
我不明白 X_test、y_test 是如何泄露到 X_train 或 y_train 中的,反之亦然。
当使用 MinMaxScaler() 进行数据准备时,您在使用 MinMaxScaler 等缩放器(MinMaxScaler、RobustScaler、StandardScaler 和 Normalizer)对数据进行转换,您希望模型更好地收敛。
换句话说,X_train 的信息如何干扰 X_test,反之亦然。对于泄露到 y_train 和 y_test 以及反之亦然,也有相同的问题。
此外
从朴素模型来看,我不明白当 cv 已经类似地分配时,RepeatedKFold 如何导致泄漏,当数据在 scores=cross_val_score(model,X,y,……..cv=cv….) 中使用时,存在泄漏。
从管道模型来看
我不明白 X 和 y 的信息是如何泄露的,因为 X 和 y 没有拆分。
问题/总结 – 关于泄漏
有两种方法
* 一种是使用数据准备来加快模型收敛,但我不明白当数据已经分配时,转换如何减少泄漏。
* 另一种是使用管道。同样,我不明白将包含一系列命令的管道与列表放在一起如何导致 X 和 y 之间的干扰。
我确信有一个简单的方法,即仅仅分配变量仍然会导致泄漏,除非我准备数据和/或使用管道。
谢谢你,
悉尼的Anthony
如果你使用测试集的知识来缩放训练集,例如你使用整个数据集归一化并计算最小值/最大值,那么你可能会从测试集泄露到训练集。
管道确保转换只在训练集上进行拟合。
尊敬的Jason博士,
根据您的回答和博客,这是我的理解。
在“使用正确数据准备的训练-测试评估”标题和“将这些结合起来,完整的示例如下”副标题下,通过转换执行的防泄漏准备是在单独的 X_train 和 X_test 上进行的,而不是在整个 X 特征上。
据我理解,X_train 的标准差不一定与 X_test 的标准差相同,两者也都不与整个 X 的标准差相同。
然后,为了进行预测,您将转换您希望预测的值。
再次感谢,不胜感激。
悉尼的Anthony
是的,如果我们在整个数据集上拟合转换,就会发生泄漏。如果我们只在训练集上拟合转换,就不会发生泄漏。
尊敬的Jason博士,
谢谢,不胜感激。
悉尼的Anthony
不客气。
尊敬的Jason博士,
当我提交问题时,由于响应缓慢,我的网页浏览器出现错误。我在页面底部提交了相同的问题。请忽略上面的提交,因为相同的提交已在底部提出。
悉尼的Anthony
你好,Jason。
感谢您对 RFE 的见解。
这个问题可能已经被问过,但我正在寻求关于使用 CV 进行 RFE 过程的澄清。
从“探索特征数量”部分来看
假设我们有训练数据,并将其分成 5 折。我们暂时不考虑测试数据。
使用第 1-4 折,我们使用 RFE 运行,选择 3 到 5 个特征。我相信它会使用最佳的 5 个特征运行模型,记录第 5 折上的分数,然后运行 4 个特征的模型,记录第 5 折上的分数,对 3 个变量也做同样的事情。然后我们继续使用第 2-5 折,在第 1 折等上进行评估。
我说的是,在此折中选择的 5、4 和 3 个特征可能与我们在其他训练折中选择的特征不同,对吗?
如果是这样,当我们使用整个训练数据来创建模型并在保留/未见训练数据上运行时,如果它在 3、4 和 5 个所选特征的每个折上返回不同的特征,模型将如何选择要使用的特征?
太棒了!
谢谢!
谢谢杰森,非常有用的内容!!
我有一个问题。一旦您通过管道运行特征选择、交叉验证和网格搜索,如何访问最佳模型以在 x_test 上进行预测?
您可以使用您发现最适合您数据集的技术和配置来拟合一个新的最终模型。
https://machinelearning.org.cn/train-final-machine-learning-model/
谢谢杰森,是的,这对我很有意义。但我不确定当我在循环中使用 'cross_val_score' 和 'pipeline' 时(如您在“RFE for Classification”中所示),如何访问选定的特征。
我试图通过循环实现的是
1. 对于超参数和 RFE 的每种组合,运行模型拟合和 cross_val_score
2. 选择与此模型相关的最佳特征并转换输入
3. 使用仅选定的特征拟合新模型并使用它与测试数据进行预测
4. 检查准确性,以便在箱线图中,我还可以可视化每个模型运行在测试数据上的表现。
我拥有完全独立的验证数据,我将在最后用于“最佳模型”的独立验证。
但我不知道在调用 cross_val_score 之后如何获取选定的特征。
谢谢!!
您不需要访问特征,因为 RFE 会成为您建模管道的一部分。
您可以手动选择 RFE 选择的特征,但重点是您不需要。RFE 会为您完成。
不错的文章。谢谢
1. 当我们使用 RFECV 自动选择特征数量时,我们如何知道 RFECV 方法选择了哪些特征?
2. 我们可以先使用 RFECV,然后使用带有 RFECV 选定特征的模型进行交叉验证吗?
如果您愿意,可以手动运行该方法并使其打印所选特征。
是的。
谢谢。您说的手动是指使用 RFE 方法吗?
我的意思是,您可以独立运行 RFE 或 RFECV 方法,并查看它正在做什么。
好的。非常感谢。
信息量很大的文章。谢谢您的发表。
我有一个关于混合数据集的问题,即它既有数值输入,也有分类输入,并且需要分类输出。如果我将数据集分成两个文件,一个包含数值数据,另一个包含分类数据,然后对每个数据集运行适当的特征选择方法(例如 ANOVA 和 Chi Squared),那么使用从每种数据类型最重要的特征中获取的信息来更改原始数据集以选择适当的字段是否合适?我想知道这是否合适,或者它是否会引入偏差?
谢谢!
尝试一下,看看它是否比 RFE 或使用所有特征表现更好。
这是一种偏见,希望能找到一种在交叉验证折叠中完成它的方法。
尊敬的Jason博士,
“探索基础算法”副标题下的代码,特别是
第 25-27 行。这与您书中使用的代码类似,列表 15.21 第 187 页。
我们让 RFE 使用 LogisticRegression 选择最多五个特征。
DecisionTreeClassifier 如何与 RFE(LogisticRegression) 配合使用。
谢谢你,
悉尼的Anthony
决策树将采用 RFE 选择的特征并拟合模型。
逻辑回归模型仅由 RFE 用于评估 RFE 选择的不同特征子集。
尊敬的Jason博士,
谢谢您的阐述。不胜感激。
悉尼的Anthony
不客气。
尊敬的Jason博士,
再次感谢您的回复。我想将您的回复应用于“机器学习数据准备”一书第 186 页(398 页中的 203 页)的列表 15.21,我强烈推荐这本书。
为了更好地理解,应用您之前的回答
第一行,rfe 根据 DecisionTreeClassifier 使用不同的子集选择特征。选定的特征在 DecisionTreeClassifier = 模型中进行评估。
谢谢你,
悉尼的Anthony
是的,在 RFE 中使用与 RFE 之后相同的模型可能是一个好主意。
尊敬的Jason博士,
谢谢您,它回答了我的问题,不胜感激。
悉尼的Anthony
感谢分享。您的博客比 sklearn 文档更好 🙂
快速提问:当我调整 n_features_to_select 参数并使用 DecisionTreeClassifier 作为估计器时,我得到的结果与您的相似,但是当我改用 LogisticRegression 时,无论 n_features_to_select 的值是多少,我总是得到相同的结果。
使用 DecisionTreeClassifier:(f 分数)
>2 0.742 (0.009)
>3 0.742 (0.009)
>4 0.741 (0.009)
>5 0.741 (0.009)
>6 0.741 (0.009)
>7 0.740 (0.010)
>8 0.739 (0.010)
>9 0.739 (0.010)
使用 LogisticRegression:(f 分数)
>2 0.742 (0.009)
>3 0.742 (0.009)
>4 0.742 (0.009)
>5 0.742 (0.009)
>6 0.742 (0.009)
>7 0.742 (0.009)
>8 0.742 (0.009)
>9 0.742 (0.009)
原因可能是什么?
也许它作为管道的一部分不起作用?
谢谢
谢谢!
也许您的逻辑回归示例中有 bug?
也许改变特征不会影响模型技能(不太可能)?
嗨,Jason,
您的文章是很好的信息来源。我有一个问题,如果我理解正确的话,为了使用 RFE,我们首先需要对可用数据进行归一化或标准化,以根据模型中的重要性获取正确的特征。否则,值较小的特征将具有较高的相关系数,反之亦然。这是我的理解。如果我理解错了,请纠正我。
谢谢
谢谢!
这取决于您使用的模型。如果您在 RFE 中使用树,则不需要。如果您使用逻辑回归,则可能需要。
嗨,Jason,
您的文章是很好的信息来源
谢谢!
嗨,Jason,
在调整 RFE 选择的最佳特征数量时,我们不应该在运行模型之前删除重复项吗?
也就是说,如果你只保留 2 个变量,你可能会有比使用 5 个变量更多的重复行。
这可能发生在分类特征或分类/数值特征的混合中。
非常感谢 🙂
数据清理,如删除重复的行和列通常会有帮助,请参阅此教程:
https://machinelearning.org.cn/basic-data-cleaning-for-machine-learning/
我们可以使用 RFE 算法绘制 RMSE(均方根误差)吗?
因为可能不是浮点数
我该如何绘制呢?
你会怎么画呢?
用于回归的核心 RFE 中可以使用哪些算法,以及如何计算这些算法的准确性,谢谢。
任何你喜欢的回归算法。
当尝试在核心 RF 中使用可用于回归问题而非分类的算法时,我得到此错误。
ValueError: 未知标签类型:'continuous'
我可以在代码中更改什么以避免此错误?
很抱歉您遇到问题,也许可以从上面的回归示例开始,并将其调整到您的项目中?
嗨,杰森,有没有办法查看在交叉验证期间选择了哪些特征,而不是将所有数据拟合以获取这些特征?
在我看来,“自动选择特征数量”部分中获得的准确性并不是基于您在“选择了哪些特征?”部分中获得的特征。第一部分使用 CV,第二部分拟合所有数据。
是的,对于每个折叠,如果您手动枚举并打印对象选择的特征。
但你为什么要知道呢?你关心线性回归模型在每个折叠中选择的系数吗?从不!
我的意思是,我们如何提取输出交叉验证分数的所选子集。
对不起,那是一个问题。
您可以通过手动枚举交叉验证折叠并评估您的模型,然后访问管道中的 RFE 并打印该折叠报告的特征来做到这一点。
但我问你为什么想要这些信息?它无关紧要!
我正在考虑它用于解释。想知道哪些 10 个特征被认为是最重要的。
您可以独立运行一次模型,以发现哪些特征可能很重要。
但请告诉我是否有更好的方法。谢谢您的帮助
是的,您可以在数据的训练/测试分割上运行该过程,以了解有关数据集的更多信息。
这与评估建模管道是独立的,在这种情况下,了解所选特征不会改变任何事情。
嗨,Jason,
感谢您撰写这篇有用的博客。请问,对于回归问题,我是否可以使用“DecisionTreeRegressor”作为 RFE 中的估计器,并使用“深度神经网络”作为模型?如果不行,当我想要为 DNN 算法选择最佳数据子集时,您对 RFE 中的估计器有什么建议?
提前感谢,
马苏德
当然可以。
通常,在两种情况下使用相同的算法是个好主意,但这不是规定。
谢谢亲爱的杰森。
不客气。
感谢杰森,这篇博客文章信息量很大。
我有一些问题要讨论。
在统计学家用来拟合回归模型的传统方法中。
他们会对单个特征进行 p 值测试,只选择那些倾向于显著的变量,例如 p<0.15,作为第一轮特征筛选。
然后,他们将使用多重回归,并使用前向或后向消除进行最终的特征选择。
您有关于哪种方法给出更好结果的信息吗?比较单独的 RFE,或者在 RFE 之前先进行单个特征筛选,或者 RFE 与前向/后向消除的比较。
没有最好的方法
https://machinelearning.org.cn/faq/single-faq/what-feature-selection-method-should-i-use
在使用更复杂的模型,例如 XGBoost 时,进行 RFE 是否值得?
是的,如果您不使用 XGBoost。
你好 Jason,
首先,感谢您的出色工作!我通过您的网站学到了很多知识。我无法用言语表达我有多么感谢您。
我在自己的数据集上实现了您的管道。当我检查不同的特征重要性时,所有 47 个特征都同样重要。看起来我有一些数据泄露,不是吗?
不客气。
也许吧,或者技术无法区分您的特征——例如,您的问题可能无法预测。
嗨 Jason
我有一个问题。假设我们正在使用 RFE,但我们还没有选择特定的模型来预测我们的输出。也就是说,我们有一系列可能性,无论是 SVM、梯度提升还是随机森林等(分类,但回归也有不同的列表)。当我们对 RFE 执行交叉验证并将其设置为自动选择特征数量时,我们是否必须为每个模型重复此操作?
此外,您将决策树同时用作估计器和模型,我们可以使用不同的模型但将决策树保留为估计器吗?例如)估计器=决策树 模型=SVM
我们还可以使用不同的估计器吗?
啊哈。我错过了结尾。感谢这篇文章。我应该在提问前读完。
跟进
在进行特征选择并使用 RFE 和交叉验证找到最佳特征时,当我们测试其他机器学习算法进行实际数据建模时,我们是否会遇到不同模型与不同选择特征配合更好的问题?
在文章的末尾,您比较了具有相同模型的不同估计器。假设我们选择最好的一个,但后来我们仍然必须使用 Gridsearch 优化模型的超参数。我们如何知道这仍然是我们最好的模型?我们如何知道如果我们使用网格搜索优化模型中的超参数,其他估计器/模型组合是否会更好?我们什么时候才能安心地停止?
是的。
测试所有,使用错误率最低的结果。
当结果足够好时,或者当您没有想法时,或者当您没有时间时,停止。
不客气。
如果您愿意,可以在内部和外部使用不同的模型,使用相同的模型可能更可取。
在考虑一组模型时,每个模型都应在相同的建模管道中考虑(将转换应用于数据,如 rfe)
我们会在应用 RFE 之前移除高度相关的特征吗?
可能。
这取决于您最终使用的模型。也取决于您是否有大量特征并正在寻找加快管道的方法。
# 定义数据集
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# 创建管道
rfe = RFECV(estimator=DecisionTreeClassifier())
model = DecisionTreeClassifier()
pipeline = Pipeline(steps=[(‘s’,rfe),(‘m’,model)])
# 评估模型
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring=’accuracy’, cv=cv, n_jobs=-1, error_score=’raise’)
# 报告表现
print(‘Accuracy: %.3f (%.3f)’ % (mean(n_scores), std(n_scores)))
我想知道 RFECV 有多少特征,但由于它在管道对象中,我无法获取支持和排名属性。请帮忙!!
如果您仅在训练集上运行 RFE,您可以看到选择的特征——正如我们在上面的教程中所做的那样。
当作为管道的一部分使用时,我们不关心选择了什么,就像我们不关心特定决策树的外观一样——只关心它表现良好。
嗨,
感谢这个不错的教程。
我有一件事不明白。我们在管道内部使用 RFE,然后使用 gridsearchCV 找出最佳特征数量,例如 [2,5,10]。
所以我的理解是,gridsearchCV 会将数据分成 k 份。使用 k-1 个子集进行训练并对其应用 RFE 以选择表现最佳的特征。最后在剩余的子集上进行评估。重复相同的步骤 k 次以找出平均模型性能。对 RFE 特征的每个值执行相同的过程。
我的问题是,RFE 在每个折叠中是否选择相同的特征,或者它们是否可能不同。如果后者是真的,为什么 gridsearchCV 只返回一个最佳性能参数/模型的选定特征列表。
先谢谢您了。
RFECV 将为您选择特征数量,无需同时进行网格搜索。
感谢杰森,这篇博客文章信息量很大。
我有一个问题。当我使用 RFECV 时,为什么每次运行都会得到不同的结果。有时返回 1 个特征,有时返回 15 个特征。非常感谢。
不客气。
好问题,请看这个
https://machinelearning.org.cn/faq/single-faq/why-do-i-get-different-results-each-time-i-run-the-code
嗨,Jason,
感谢您的文章。我阅读了其中一些关于特征选择的文章。
我有一个包含许多数值和分类变量的数据集。
我正在尝试检查哪些特征与目标变量(二元)具有显著性。
我尝试了各种方法,分别使用数值特征进行 ANOVA,分类特征进行卡方检验。此外,我想使用 RFE 来比较我的结果。
当我使用以下代码时
rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=7)
rfe.fit(X4,y4)
它返回一个错误——无法将字符串转换为浮点数:“ - ”。
因此,我的问题是,我需要编码分类特征吗?此外,当我检查分类变量的数据类型时,它显示为浮点数。
请告诉我。提前感谢。
不客气。
是的。在使用 RFE 之前,您必须对分类变量进行序数编码。
谢谢 Jason。我会编码我的分类变量。我以为 RFE 会自动帮我处理这些变量 🙂
另一个问题是,如果我的目标是了解哪些特征与目标变量具有显著性,而不是进行预测,我认为使用 RFE 或任何其他过滤方法(例如卡方检验、ANOVA)应该足够了。我认为我不需要创建模型,但如果我的理解不正确,请告诉我。
此外,还有其他方法可以找出哪些特征与目标变量具有显著性吗?
不客气。
您可以计算每对输入和目标变量的统计检验并比较它们的结果。显著性可能与最佳性能相关,也可能不相关。
是的,这可能会有帮助。
https://machinelearning.org.cn/feature-selection-with-real-and-categorical-data/
谢谢你,Jason。
抱歉,我还有一个问题。我被我的问题困住了。
我正在尝试对我数据集中的分类变量进行编码,但我不知道如何将它们重新放回同一个数据框中。例如,在我的数据框中,2 个特征是分类的,3 个是名义的,当我使用 OrdinalEncoder 或 Onehotencoder 时,它只期望分类列。因此,当编码完成后,我如何保留编码后的列和 3 个名义特征?我还阅读了您关于 columntransformer 的文章,但是由于我没有创建模型,只想使用 RFE,我该如何进行?您的示例使用了管道方法,因此不确定如何进行。
好问题,您可以使用 columntransformer
https://machinelearning.org.cn/columntransformer-for-numerical-and-categorical-data/
嗨 Jason,感谢您的精彩帖子!我有一个关于在 RFE 中使用 sklearn MLPRegressor 作为模型的问题。看起来 RFE 无法处理神经网络作为模型,是真的吗?因为我在 RFE 中运行 MLPRegressor 模型时收到此错误消息。
###运行时错误:分类器未暴露“coef_”或“feature_importances_”属性###
请帮忙……提前感谢!
我不知道,抱歉。我没有尝试过。
嗨 Jason,您能否也建议我,如果我有一个具有多个输出的回归问题,我应该使用哪种特征选择方法。因为您编写的几乎所有未来选择方法,基于过滤和封装的,都只适用于多个输入对一个输出的情况。
谢谢 🙂
也许可以尝试 RFE,也许可以尝试这里描述的一些回归方法
https://machinelearning.org.cn/feature-selection-with-real-and-categorical-data/
嗨 Jason,这非常有帮助,谢谢!我有一个问题。如果用于分类,我们如何知道封装分类器用于判断性能和特征重要性的性能指标?我问这个问题的原因是,如果我们有不平衡的类别,如果封装分类器使用“准确率”,那么最重要的特征可能并不是我们真正想要的,我们可能希望使用例如 AUC。您能对此有所启发吗?谢谢!Tash
这比那简单。
最不重要的特征是根据内部模型确定的这些特征的重要性来移除的。而不是内部模型在数据集上的性能。
嗨,Jason,
在评估 MAE 时,我们是否应该考虑 STD?因此,如果对应的 std 与其余部分相比非常高,我们可能会丢弃 MAE 最小的配置。
提前感谢。
如果您正在计算平均 MAE,那么报告平均 MAE 和标准差 MAE 是一个好主意。否则就不是。
嗨 Jason,您能解释一下逻辑回归如何为每个特征提供重要性得分吗?
谢谢
系数可以直接解释为变量重要性分数。或者至少其绝对值可以。
好的,谢谢。
那么如果我们是在无监督设置中工作,没有标签,那么可以使用哪些估计器呢?
此外,在这种情况下,我们可以使用自编码器进行特征选择吗?
抱歉,我对无监督学习的特征选择了解不多——我想这取决于无监督学习问题的类型。
如果没有目标变量,那么就不能使用统计相关性或子集评估进行特征选择。
自编码器将执行一种自动特征提取,也许这对您有用。
如何将 RFE 应用于多输出,例如
X = data.drop(['Mi','P', 'T'], axis=1)
y = data[['Mi','P', 'T']]
以及如何评估这类模型
我不确定 RFE 是否支持多输出。
或许可以试试看?
嗨,Jason,
非常感谢这篇精彩的文章。
我有两个问题;我们能否将 RFE 方法用于仅包含分类变量(70 个变量)的数据集?此外,其中一些变量是序数变量。我们应该在 RFE 之前还是之后对这些序数变量进行独热编码?
先谢谢您了。
是的。
也许可以先尝试序数编码。
嗨,Jason,
很棒的文章。我关注您的工作已经很长一段时间了。我一直在寻找一些技术来从包含超过 18,000 个变量(连续)的数据集中找出相关/重要的特征。由于 RFE 需要数年才能计算出来。您能推荐一些我可以尝试的技术吗?
先谢谢您了。
谢谢!
也许可以从一个快速/简单的线性方法开始,比如与目标的关联。
嗨,Jason,
假设,
如果我通过 for 循环 i (2, 9) 分别选取 2、3、4……9 个特征,最终选取 10 个特征,并打印它们在 k 折交叉验证中的结果以查看其性能。
我如何获取每个模型所选特征的名称?假设,选取 3 个特征时,这 10 个特征中选取了哪三个特征?我如何获取这些特征的名称?
请告诉我。
此致
阿希克
您可以使用训练-测试分割重新运行 RFE,然后使用 RFE 报告的数组索引将其放入列名数组中,或者手动映射它们。
请参阅上面“选择了哪些特征”部分。
谢谢您的教程。
对不起,我是 Python 新手,但如何从管道中获取所选特征?
请参阅“选择哪些特征”部分。
嗨 Jason!我有一个问题。我们如何将 RFE 与 HistGradientBoostingRegressor 应用?它会报错,因为我们可能无法直接使用 HistGradientBoostingRegressor 获取特征重要性!
据我所知,RFE 可以直接与 HistGradientBoostingRegressor 一起使用,也许您的代码中有错误。
或许这些提示会有帮助
https://machinelearning.org.cn/faq/single-faq/can-you-read-review-or-debug-my-code
先生,请指导如何进行比较?请回复
也许可以尝试一下,看看它在您的数据集上是否有效,并与其他方法进行比较。
所有寻找 SHAP 进行特征选择(和超参数调整)的人,我建议使用 shap-hypetune (https://github.com/cerlymarco/shap-hypetune)。
一个用于梯度提升模型的超参数调整和特征选择的 Python 包。
它支持使用 RFE 或 Boruta 进行特征选择,并使用网格或随机搜索进行参数调整。
感谢分享。
嗨,Jason,
关于 RFE 作为包装器类型特征选择算法的精彩教程!
一个问题,与您探索特征数量的部分有关。当 RFE 通过参数“n_features_to_select”执行特征选择时,它总是保留最好的特征吗?
我的意思是,我不能强制 RFE 在定义“n_features_to_select”的总量时使用特定的特征“子集”吗?
无论如何,我的经验是我对使用 RFE 的“便利性”感觉不太舒服
——您不能将其用于所有 Keras 模型实现,除了其他不支持;coef_、feature_importances_ 作为拟合信息的 Sklearn 模型。
——所选特征的结果有时对于某些估计器(模型)来说很奇怪
我宁愿使用“permutation_importance”,因为它是一个更鲁棒的函数(即使来自 Sklearn)并且更灵活地与更多模型(例如 keras 模型包装器)一起使用,我认为它的性能更好
谢谢
没错,它将被强制使用指定的最佳 n 个特征。
先生,请指导我如何比较?请回复
具体比较什么?
多么棒的文章!我对 sklearn.feature_selection 很着迷,我在 Kaggle 的 titanic_survivors 上试用了它,但我要求选择的三个主要特征在向前或向后时并不相同。我很想知道为什么会发生这种情况。
算法的改变会导致所选特征的改变,因为特征之间的比较是相对的、随机的/嘈杂的。
嗨 Jason,很棒的教程。
您能帮我一下吗?好的,您通过交叉验证找到了最佳的 K(例如 K=3)。现在,我们需要做的是使用所有数据(除了测试集)重新训练,使用该 K(K=3)。然后,在评估测试集上的性能之后,我们再次使用训练集 + 测试集重新训练,再次使用 K=3,这就是您的最终模型(您投入生产的模型)。
我的问题是,为什么每个人都对知道选择了哪些特征如此感兴趣?在我看来,我们实际上并不关心选择了哪些变量(当我们使用交叉验证(CV)时,我们关心的是流程,而不是每个折叠中选择的具体变量;我们只希望过程是稳健的)。即使在 K=3 的 CV 的特定迭代中,每次也会选择不同的变量,因为每次迭代都使用不同的数据集!
实际上,如果 K=3 是最好的(并且在使用所有数据(训练+测试)进行训练时选择的特征是 A、B 和 C),那么当我们获得新数据并重新训练时,情况可能会发生变化(我们可以保持 K=3,但现在,由于我们有更多数据,因此数据集不同,现在选择的特征可能是 B、E 和 F)。事实上,这完全没问题,因为我们只关心流程,而不是具体细节……对吗?
好文章!如果我要比较不同的模型,我是否会希望在 RFECV 中为每个模型使用相同的估计器,以便每次都有相同的预测器,还是探索每个模型在 RFECV 中的“最佳估计器”?
你需要相同的度量标准来进行公平比较。举个例子,你不能在数值上比较 RMSE 和 MSE,因为一个是另一个的平方根。RFE 会告诉你,在相同的输出下,哪些输入子集可以帮助模型做得最好。记住这一点,你应该了解如何进行交叉验证,以便进行比较。
请记住,SVM-RFE 是一项专利技术。未经许可使用 SVM-RFE(自行编写或使用 SKLEARN 中编写的)将使您面临侵权责任。问问英特尔吧。他们正在被 Health Discovery 起诉。
谢谢分享。我不是律师,但我找到了专利文件,它似乎去年已经过期了:https://patents.google.com/patent/US8095483B2/en
是否可以应用于 KNN、SVM、Bagging 等?
为什么不?
谢谢,Jason,一如既往的出色工作!
我有一个小问题。
我们如何知道要选择多少个“最佳”特征?
你不知道。这更像是一种权衡,需要通过实验来证实。
嗨,Jason,
我们可以在 RFE 中使用 ANN 模型作为估计器吗?当我尝试将 ANN 作为估计器时,它给我以下错误:AttributeError: 'Sequential' object has no attribute '_get_tags'
对此有什么想法吗?
这篇帖子会有帮助:https://machinelearning.org.cn/use-keras-deep-learning-models-scikit-learn-python/
嗨,Jason,
在这里,你使用了决策树。是否可以在 RFE 中应用其他类型,如 KNN、XGBooster?
谢谢。在尝试打印这份材料进行学习时,发现有些内容重叠,不清楚。请问如何打印。
嗨 Meenakshi……博客内容并未针对打印目的进行优化。
亲爱的 Jason,
感谢这篇有用的文章。
我将这段代码用于一个回归问题。我得到了如下的负均值:
>2 -8.26728 (0.21538)
>3 -5.32587 (0.29661)
>4 -3.35181 (0.41920)
>5 -2.82741 (0.39231)
>6 -2.29025 (0.35978)
>7 -2.09409 (0.27335)
>8 -1.93794 (0.19657)
>9 -1.97243 (0.22962)
>10 -1.93483 (0.18773)
我的值是对的吗?我应该只得到正均值吗?如果正确,哪一个特征数量是最好的?是对应 8 个特征的那个吗?
嗨 Kelly……在 scikit-learn 中计算时,一些模型评估指标,如均方误差 (MSE),可能会是负值。
这令人困惑,因为像 MSE 这样的误差分数实际上不能为负,最小值为零或无误差。
scikit-learn 库有一个统一的模型评分系统,它假定所有模型分数都最大化。为了使这个系统适用于最小化的分数,如 MSE 和其他误差度量,最小化的分数通过取负值来反转。
这也可以在指标的规范中看到,例如,在指标名称“neg_mean_squared_error”中使用了“neg”。
在解释负误差分数时,你可以忽略符号并直接使用它们。
你可以在这里了解更多
模型评估:量化预测质量
这种使用 RFE 的特征选择是否仅适用于具有 feature_importances_ 或 coef_ 内部属性的模型?
如果是这样,我认为我们不能将此方法用于 MLPRegressor (MLPR) 或 HistGradientBoostingRegressor (HGBR),因为它们不具有这些属性。
你知道我们如何为 MLPR、HGBR 添加 feature_importances_ 等新函数吗?
嗨 ykcho……以下资源可能会提供帮助
https://towardsdatascience.com/powerful-feature-selection-with-recursive-feature-elimination-rfe-of-sklearn-23efb2cdb54e
嗨 James。我想再次确认一下。你说这篇文章可能会提供清晰的解释。
但是,那篇文章只考虑了 RandomForest 模型,并且说所有 sklearn 模型都有 'coef_' 或 'feature_importances_'。但是,据我所知,这是错误的。我提到的模型 (MLPR, HGBR) 没有这些属性。
所以,我想再次询问你“清晰的解释”的含义。
嗨 James。我想再次确认一下。你说这篇文章可能会提供清晰的解释。
但是,那篇文章只考虑了 RandomForest 模型,并且说所有 sklearn 模型都有 'coef_' 或 'feature_importances_'。但是,据我所知,这是错误的。我提到的模型 (MLPR, HGBR) 没有这些属性。
所以,我想再次询问你“清晰的解释”的含义。
RFE 不是一个好的封装器方法。
RFE 有点像混合体。它看起来和行为都像一个封装器,类似于向后选择。但它的主要缺点是变量选择本质上是单变量的。它使用单变量的优良性度量来对变量进行排序。从这个意义上说,它表现得像一个过滤器。
我喜欢这种特征选择方法的描述:
过滤器:快速的单变量度量过程,将单个自变量与因变量关联起来。过滤器可以是线性的(例如,皮尔逊相关系数)或非线性的(例如,单变量树模型)。过滤器的计算复杂度通常随变量数量线性增长。我们希望它们非常快,所以我们首先使用过滤器来剔除许多候选变量,然后使用封装器。
封装器:之所以这样称呼,是因为特征选择方法中“封装”了一个模型。一个好的封装器是多变量的,它会按照多变量能力对变量进行排序,从而消除相关性。封装器会构建许多模型,并且其计算复杂度随变量数量非线性增长。最好使用一个快速、简单的非线性模型作为封装器(例如,深度约为 5 的单个决策树,包含约 5 棵简单树的随机森林,包含约 20 棵简单树的 LGBM)。你使用什么模型作为封装器(DT、RF、LGBM、Catboost、SVM……)其实并不重要,只要它是一个非常简单的非线性模型即可。在执行适当的封装器之后,结果是按多变量重要性排序的变量列表。RFE 不会提供这样的结果。
在实践中,你可能会创建数千个候选变量。然后进行特征选择以获得一个考虑了相关性的短列表。你首先进行一个过滤器,一个单变量度量,将候选变量缩减到大约 50 到 100 个。然后运行一个(适当的)封装器,得到按多变量重要性排序的列表,你通常会发现大约 10 到 20 个变量足以构建一个好的模型。然后你将这个少量变量用于模型探索、调整和选择。
当然,许多非线性模型本身会给你一个按重要性排序的变量列表,但是用数百或数千个候选变量运行一个完整的复杂非线性模型是不切实际的。这就是为什么我们将特征选择作为减少变量的步骤,然后再探索最终的非线性模型。
RFE/RFECV 介于两者之间,是一个可怜的旁支。它的变量排序本质上是单变量的,像一个过滤器。它不消除相关性,也像一个过滤器。但它有一个模型封装器,所以它看起来像一个封装器。它决定了多少变量排名第一,其余的按单变量重要性排序,但不按多变量重要性对排名第一的变量(或任何变量)进行排序。
我的观点:RFE 是一个流行但糟糕的封装器。请使用 sequentialfeatureselector。
感谢您的反馈,steve c!如果您需要我们澄清博客和/或任何其他内容中的任何项目,请告诉我们。
嗨,Jason,
非常感谢这篇文章以及所有您精彩的内容!
我还阅读了您的“XGBoost 中的特征重要性和特征选择”文章,并使用了这两种方法(RFE 和 feature_importances_ XGBoost 函数)来识别给定数据集中最具影响力的特征,我正在为此数据集创建回归模型。对于 RFE 方法,我将 XGBoost 作为估计器。这两种方法最终识别出不同的特征。例如,我要求每种方法提供前 10 个特征,但只有大约一半是相同的。其他的都不同。尽管我使用了两种计算方式不同的方法,但我期望结果有更多的相似性,因为两种方法的目的相同。(尤其是我也使用 XGBoost 作为 RFE 方法的估计器)
对此您有什么解释吗?
谢谢!
嗨 Sam……感谢您的反馈!您是直接使用了教程中的代码还是自行编写的?
嗨 Jason,非常感谢您的文章。
我有一个问题,RFE 和 RFECV 应该给出相同或相似的结果吗?在我的案例中,RFECV 的表现比 RFE 差。
嗨 Tati……非常欢迎!
RFE
(递归特征消除)和RFECV
(带交叉验证的递归特征消除)是sklearn
库中可用的特征选择技术。它们都旨在根据给定估计器的性能递归地移除特征并对其进行排名。然而,它们之间存在一些关键区别:1. **交叉验证**
–
RFE
简单地根据模型导出的重要性消除特征。默认情况下它不使用交叉验证。–
RFECV
使用交叉验证执行特征消除。在每一步,它都会移除一个特征并计算交叉验证的性能,以确定移除该特征是否有益。2. **稳定性**
– 由于
RFECV
使用交叉验证,它倾向于提供比RFE
更稳定和稳健的选定特征集,尤其是在数据集存在一定方差或噪声时。3. **计算时间**
–
RFECV
可能比RFE
的计算成本更高,因为它使用交叉验证,这意味着对于每个特征子集,都需要多次拟合模型。4. **结果**
– 由于
RFECV
中的交叉验证步骤,如果数据集存在噪声或模型的性能因不同的训练-测试分割而异,它选择的特征可能与RFE
不同。总之,虽然两种方法都旨在消除不太重要的特征,但
RFECV
通过使用交叉验证提供了更稳健的特征排名。然而,这会增加计算时间。根据具体数据集和问题,RFE
和RFECV
可能会给出相似或不同的结果。始终建议在单独的保留集上或使用一些外部验证标准来验证所选特征。你好,感谢您的这篇文章。
我尝试了 RFE,结果显示具有最高准确率的特征子集是 21。后来,我尝试使用所有特征进行分类。令人惊讶的是,21 个特征的子集在分类过程中并没有获得最高分数。你知道为什么会这样吗?
嗨 hartati……非常欢迎!每次试验可能存在差异。您多次试验的平均结果如何?
我们如何根据递归特征消除来选择最重要的特征,而无需实际提及要选择的特征数量?
嗨 Yustina……以下资源可能对您有用
https://machinelearninginterview.com/topics/machine-learning/recursive-feature-elimination-for-feature-selection/
https://scikit-learn.cn/stable/modules/feature_selection.html
此外,根据您的应用,深度学习方法可能在无需大量特征消除的情况下提供出色的性能。
你好,
我正在尝试将 RFE 应用于我自己的问题。简而言之,我有 92 个观测值,每个观测值都属于 6 个类别之一。对于每个观测值,我有 610 个特征(在这种情况下是各种化学物质的浓度)。我希望选择在每个六个类别中独特存在的特征(化学物质)。我首先将此数据集转换为每个 6 个类别的二元分类问题(1 = 感兴趣的类别;0 = 所有其他类别)。然后我观察到有几个特征是该感兴趣类别独有的,并且在所有其他类别中都不存在——我假设这些特征对模型很重要,但是,我还发现这些特征彼此高度相关。尽管如此,我仍在数据集上训练了随机森林、SVC 和逻辑回归模型,然后运行了 RFE(因为有人建议 RFE 能够处理相关变量;具体来说,我运行的是 sklearn 中的 RFE)。然而,当我检查 RFE 选择的特征时,它并不完全合理。首先,RFE 似乎选择了在感兴趣类别中独特存在的特征(这有道理)。它还选择了在感兴趣类别中独特不存在的特征(也有些道理)。但它也选择了一些在其他(0)类别中零星存在,而在感兴趣类别中单个观测值中不存在的特征。这对我来说毫无意义,因为还有其他特征在我的感兴趣类别中独特存在/不存在。更重要的是,这些“奇怪的”特征被我的两个或更多选定分类器选择。我的方法有问题吗?我应该尝试其他方法吗?我应该在运行 RFE 之前尝试清理数据集中的相关特征吗,即使我以为 RFE 可以处理相关特征?
嗨 Tara……请将您的问题限定为一个,以便我们更好地帮助您。
嗨,我有一个问题。我尝试从 RFE 和 RFE 的原始估计器(例如 LightGBMClassifier)中获取特征重要性分数,结果显示 RFE 的特征重要性和排名与 LightGBM 的特征重要性不同。你知道为什么吗?谢谢。
嗨!感谢您提供这篇内容丰富的文章。
我想知道在训练模型时是否必须使用 pipeline。是否可以跳过 pipeline( steps= …) 并直接交叉验证 rfe-estimator,如下所示:
rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=5)
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(rfe, X, y, scoring=’accuracy’, cv=cv, n_jobs=-1, error_score=’raise’)
嗨 Roger……在机器学习中,尤其是在 scikit-learn 中,通常建议使用管道(pipeline),原因有几点,包括确保所有转换在数据的不同部分都一致应用,以及简化代码。但是,如果您对如何应用转换很小心,则不严格要求使用管道。让我们讨论两种方法以及何时您可能更喜欢其中一种。
### 使用管道
管道有助于简化按顺序应用多个步骤的过程,例如特征选择后进行模型训练。这对于确保在交叉验证期间正确应用所有转换并避免数据泄漏特别有用。
以下是如何使用
RFE
和DecisionTreeClassifier
设置管道:python
from sklearn.pipeline import Pipeline
from sklearn.feature_selection import RFE
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import RepeatedStratifiedKFold, cross_val_score
# 使用 RFE 和决策树分类器创建管道
pipeline = Pipeline(steps=[
('feature_selection', RFE(estimator=DecisionTreeClassifier(), n_features_to_select=5)),
('classification', DecisionTreeClassifier())
])
# 定义交叉验证方法
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# 使用交叉验证评估管道
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print(f'平均准确度: {n_scores.mean()}')
### 跳过管道
可以跳过管道并直接使用
RFE
进行交叉验证,如您示例所示。这种方法是有效的,但如果存在多个预处理步骤,可能会出现潜在问题。以下是您的参考示例:python
from sklearn.feature_selection import RFE
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import RepeatedStratifiedKFold, cross_val_score
# 使用决策树分类器创建 RFE 对象
rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=5)
# 定义交叉验证方法
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# 直接使用交叉验证评估 RFE
n_scores = cross_val_score(rfe, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print(f'平均准确度: {n_scores.mean()}')
### 注意事项
1. **数据泄漏**:当使用多个预处理步骤时,确保每个步骤在交叉验证折叠内正确应用以避免数据泄漏至关重要。管道通过将所有步骤封装在一个对象中来帮助减轻这种风险。
2. **代码简洁性和可维护性**:使用管道可以简化代码并提高其可读性。它还使得将来添加或修改步骤变得更容易。
3. **一致性**:管道确保对训练数据和任何新数据应用完全相同的步骤。当单独应用步骤时,这种一致性更难维护。
### 结论
虽然跳过管道并直接交叉验证
RFE
估计器是正确的,如您示例所示,但使用管道通常是确保一致性、避免数据泄漏和维护更简洁代码的更好实践。如果您的预处理最少且您对工作流程充满信心,那么跳过管道可能是可以接受的。但是,对于更复杂的工作流程或为了遵循最佳实践,建议使用管道。