1.13. 特征选择#

sklearn.feature_selection 模块中的类可用于对样本集进行特征选择/降维,以提高估计器的准确性分数或提高其在非常高维数据集上的性能。

1.13.1. 去除低方差特征#

VarianceThreshold 是一种简单的基线特征选择方法。它去除所有方差不满足某个阈值的特征。默认情况下,它去除所有零方差特征,即在所有样本中具有相同值的特征。

例如,假设我们有一个具有布尔特征的数据集,我们想去除所有在超过 80% 的样本中为 1 或 0(开或关)的特征。布尔特征是伯努利随机变量,此类变量的方差由下式给出:

\[\mathrm{Var}[X] = p(1 - p)\]

因此,我们可以使用阈值 .8 * (1 - .8)

>>> from sklearn.feature_selection import VarianceThreshold
>>> X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
>>> sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
>>> sel.fit_transform(X)
array([[0, 1],
       [1, 0],
       [0, 0],
       [1, 1],
       [1, 0],
       [1, 1]])

正如预期的那样,VarianceThreshold 已删除第一列,其包含零的概率为 \(p = 5/6 > .8\)

1.13.2. 单变量特征选择#

单变量特征选择通过基于单变量统计检验选择最佳特征来工作。它可以被视为估计器的预处理步骤。Scikit-learn 将特征选择例程作为实现 transform 方法的对象公开

  • SelectKBest 去除除得分最高的 \(k\) 个特征之外的所有特征

  • SelectPercentile 去除除用户指定的得分最高的特征百分比之外的所有特征

  • 使用每个特征的常见单变量统计检验:错误肯定率 SelectFpr、错误发现率 SelectFdr 或全族错误率 SelectFwe

  • GenericUnivariateSelect 允许使用可配置的策略执行单变量特征选择。这允许使用超参数搜索估计器选择最佳的单变量选择策略。

例如,我们可以使用 F 检验来检索数据集的两个最佳特征,如下所示:

>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import f_classif
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> X_new = SelectKBest(f_classif, k=2).fit_transform(X, y)
>>> X_new.shape
(150, 2)

这些对象将评分函数作为输入,该函数返回单变量分数和 p 值(或仅针对 SelectKBestSelectPercentile 返回分数)。

基于F检验的方法估计两个随机变量之间的线性相关程度。另一方面,互信息方法可以捕捉任何类型的统计依赖关系,但由于是非参数的,它们需要更多样本才能进行准确估计。请注意,\(\chi^2\)检验只能应用于非负特征,例如频率。

警告

注意不要在分类问题中使用回归评分函数,否则将得到无用的结果。

注意

SelectPercentileSelectKBest 也支持无监督特征选择。需要提供一个 score_func,其中 y=Nonescore_func 应在内部使用 X 来计算分数。

示例

1.13.3. 递归特征消除#

给定一个为特征分配权重的外部估计器(例如,线性模型的系数),递归特征消除(RFE)的目标是通过递归考虑越来越小的特征集来选择特征。首先,估计器在初始特征集上进行训练,并通过任何特定属性(例如 coef_feature_importances_)或可调用对象获得每个特征的重要性。然后,从当前特征集中修剪掉最不重要的特征。该过程在修剪后的集合上递归重复,直到最终达到所需的特征选择数量。

RFECV 在交叉验证循环中执行 RFE 以找到最佳特征数量。更详细地说,通过在不同的交叉验证分割(由 cv 参数提供)上拟合 RFE 选择器来自动调整选择的特征数量。RFE 选择器的性能使用 scorer 对不同数量的选定特征进行评估并汇总在一起。最后,对各折的分数进行平均,并将选择的特征数量设置为最大化交叉验证分数的特征数量。

示例

1.13.4. 使用 SelectFromModel 进行特征选择#

SelectFromModel 是一种元转换器,可以与任何通过特定属性(例如 coef_feature_importances_)或通过拟合后的 importance_getter 可调用对象为每个特征分配重要性的估计器一起使用。如果特征值的相应重要性低于提供的 threshold 参数,则认为这些特征不重要并将其移除。除了以数值方式指定阈值外,还可以使用字符串参数使用内置启发式方法查找阈值。可用的启发式方法包括“mean”、“median”以及这些方法的浮点倍数,例如“0.1*mean”。结合 threshold 条件,可以使用 max_features 参数来设置要选择的特征数量的限制。

有关如何使用它的示例,请参阅以下部分。

示例

1.13.4.1. 基于L1的特征选择#

使用 L1 范数惩罚的线性模型具有稀疏解:许多估计的系数为零。当目标是降低数据的维度以与另一个分类器一起使用时,它们可以与 SelectFromModel 一起使用来选择非零系数。特别是,为此目的有用的稀疏估计器是用于回归的 Lasso,以及用于分类的 LogisticRegressionLinearSVC

>>> from sklearn.svm import LinearSVC
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X, y)
>>> model = SelectFromModel(lsvc, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 3)

对于 SVM 和逻辑回归,参数 C 控制稀疏性:C 越小,选择的特征越少。对于 Lasso,alpha 参数越高,选择的特征越少。

示例

L1范数恢复和压缩感知#

对于一个合适的α值,Lasso 可以在满足特定条件的情况下,仅使用少量观测值就能完全恢复出非零变量的精确集合。特别是,样本数量应该“足够大”,否则L1模型的性能将随机,而“足够大”取决于非零系数的数量、特征数量的对数、噪声量、非零系数的最小绝对值以及设计矩阵X的结构。此外,设计矩阵必须显示某些特定属性,例如不能过于相关。关于使用Lasso进行稀疏信号恢复,请参阅此关于压缩感知的示例: 压缩感知:使用L1先验(Lasso)进行断层扫描重建

没有通用的规则来选择用于恢复非零系数的α参数。它可以通过交叉验证来设置(LassoCVLassoLarsCV),但这可能会导致欠惩罚模型:包含少量不相关的变量不会损害预测得分。相反,BIC(LassoLarsIC)倾向于设置较高的α值。

参考文献

Richard G. Baraniuk “压缩感知”, IEEE信号处理杂志 [120] 2007年7月 http://users.isr.ist.utl.pt/~aguiar/CS_notes.pdf

1.13.4.2. 基于树的特征选择#

基于树的估计器(参见sklearn.tree 模块和sklearn.ensemble 模块中的树的森林)可用于计算基于杂质的特征重要性,这反过来可用于丢弃不相关的特征(与SelectFromModel 元转换器结合使用)。

>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> clf = ExtraTreesClassifier(n_estimators=50)
>>> clf = clf.fit(X, y)
>>> clf.feature_importances_  
array([ 0.04...,  0.05...,  0.4...,  0.4...])
>>> model = SelectFromModel(clf, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape               
(150, 2)

示例

1.13.5. 顺序特征选择#

顺序特征选择 [sfs] (SFS) 在 SequentialFeatureSelector 转换器中可用。SFS 可以是前向或后向的。

前向-SFS 是一种贪婪过程,它迭代地寻找最佳的新特征添加到已选择特征的集合中。具体来说,我们最初从零个特征开始,找到当估计器在此单个特征上训练时最大化交叉验证分数的一个特征。一旦选择该第一个特征,我们就通过向已选择特征的集合中添加新特征来重复该过程。当达到所需数量的已选择特征时,该过程停止,这由n_features_to_select参数确定。

后向-SFS遵循相同的思想,但工作方向相反:我们不是从无特征开始贪婪地添加特征,而是从所有特征开始贪婪地从集合中移除特征。direction参数控制使用前向还是后向SFS。

顺序特征选择的细节#

通常,前向和后向选择不会产生等效的结果。此外,根据所需选择的特征数量,一种方法可能比另一种方法快得多:如果我们有10个特征并要求选择7个特征,则前向选择需要执行7次迭代,而后向选择只需要执行3次。

SFS与RFESelectFromModel的不同之处在于,它不需要底层模型公开coef_feature_importances_属性。但是,考虑到需要评估更多模型,与其他方法相比,它可能更慢。例如,在后向选择中,使用k倍交叉验证从m个特征到m - 1个特征的迭代需要拟合m * k个模型,而RFE只需要单次拟合,并且SelectFromModel总是只进行单次拟合并且不需要迭代。

参考文献

示例

1.13.6. 特征选择作为管道的一部分#

特征选择通常用作实际学习之前的预处理步骤。在 scikit-learn 中推荐的方法是使用Pipeline

clf = Pipeline([
  ('feature_selection', SelectFromModel(LinearSVC(penalty="l1"))),
  ('classification', RandomForestClassifier())
])
clf.fit(X, y)

在此代码段中,我们使用LinearSVC结合SelectFromModel来评估特征重要性并选择最相关的特征。然后,RandomForestClassifier 在转换后的输出上进行训练,即仅使用相关的特征。当然,您可以对其他特征选择方法和提供评估特征重要性方法的分类器执行类似的操作。有关更多详细信息,请参阅Pipeline示例。