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\) 检验仅适用于非负特征,如频率。

Warning

注意不要将回归评分函数用于分类问题 问题,你将得到无用的结果。

Note

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

示例

1.13.3. 递归特征消除#

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

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

示例

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参数越高,选择的特征越少。

.. rubric:: 示例

* :ref:`sphx_glr_auto_examples_linear_model_plot_lasso_dense_vs_sparse_data.py` .

.. _compressive_sensing:

.. dropdown:: L1恢复和压缩感知

  对于alpha的良好选择,:ref:`lasso` 可以在满足某些特定条件的情况下,仅使用少量观测值完全恢复精确的非零变量集。特别是,样本数量应“足够大”,否则L1模型将随机执行,其中“足够大”取决于非零系数的数量、特征数量的对数、噪声量、非零系数的最小绝对值以及设计矩阵X的结构。此外,设计矩阵必须显示某些特定属性,例如不能过于相关。

  没有通用规则来选择用于恢复非零系数的alpha参数。可以通过交叉验证(:class:`~sklearn.linear_model.LassoCV` 或:class:`~sklearn.linear_model.LassoLarsCV` )来设置,但这可能导致模型欠惩罚:包括少量不相关的变量对预测分数没有害处。BIC(:class:`~sklearn.linear_model.LassoLarsIC` )则倾向于设置较高的alpha值。

  .. rubric:: 参考文献

  Richard G. Baraniuk "Compressive Sensing", IEEE Signal
  Processing Magazine [120] July 2007
  http://users.isr.ist.utl.pt/~aguiar/CS_notes.pdf

基于树的特征选择

基于树的估计器(参见 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_ 属性。 然而,考虑到与其他方法相比需要评估更多的模型,它可能会更慢。 例如,在后向选择中,从 m 个特征到 m - 1 个特征的迭代使用k折交叉验证需要拟合 m * k 个模型, 而 RFE 只需要一次拟合, SelectFromModel 总是只进行一次拟合并不需要迭代。

参考文献

示例

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

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

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

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