1.13 特征选择

sklearn.feature_selection中的类可以用于样本集的特征选择/降维,既可以提高估计器的精度得分,也可以提高它们在非常高维数据集上的性能。

1.13.1 移除低方差特征

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

例如,假设我们有一个具有布尔特征的数据集,并且我们想要移除那些在整个数据集中特征值为0或者为1的比例超过80%的特征。布尔特征是伯努利(Bernoulli)随机变量,并给出了这些变量的方差:

因此,我们可以使用阈值.8 * ( 1 - .8)进行选择:

>>> from sklearn.feature_selection import VarianceThreshold
>>> X = [[001], [010], [100], [011], [010], [011]]
>>> sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
>>> sel.fit_transform(X)
array([[01],
       [10],
       [00],
       [11],
       [10],
       [11]])

正如预期的那样,VarianceThreshold删除了第一列,该列包含一个0的概率是

1.13.2 单变量特征选择

单变量特征选择是通过基于单变量统计检验来选择最优特征实现的。它可以看作是对估计器的预处理步骤。Scikit-learn将特征选择的程序作为实现了transform方法的对象:

  • SelectKBest 移除那些除了评分最高的 K 个特征之外的所有特征
  • SelectPercentile 移除除了用户指定的最高得分百分比之外的所有特征
  • 对每个特征使用通用的单变量统计检验:假正率 SelectFpr, 伪发现率SelectFdr, 或者族系误差SelectFwe
  • GenericUnivariateSelect允许使用可配置策略执行单变量特征选择。它允许使用超参数搜索估计器来选择最佳的单变量选择策略。

例如,我们可以对样本执行检验,只检索两个最好的特征,如下所示:

>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import chi2
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(1504)
>>> X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
>>> X_new.shape
(1502)

这些对象以一个得分函数作为输入,该函数返回单变量分数和p值(或仅用于 SelectKBestSelectPercentile):

基于F检验的方法估计了两个随机变量之间的线性依赖程度。另一方面,互换信息方法(mutual information methods )可以捕获任何类型的统计相关性,但由于非参数性,它们需要更多的样本来精确估计。

稀疏数据的特征选择

如果您使用稀疏数据(即数据被表示为稀疏矩阵),则 chi2, mutual_info_regression, mutual_info_classif 将处理这些数据,而不会使其稠密。

警告:不要使用一个回归评分函数来处理分类问题,你会得到无用的结果。

示例
单变量特征选择
F检验与互信息比较

1.13.3 递归特征消除

给定一个外部的估计器,可以对特征赋予一定的权重(比如,线性模型的相关系数),递归特征消除(RFE)通过考虑越来越小的特征集来递归的选择特征。 首先,估计器在初始的特征集合上训练并且通过 coef_属性或者feature_importances_获取每一个特征的重要性。 然后,从当前的特征集合中移除最不重要的特征。在特征集合上不断的重复递归这个步骤,直到最终达到所需要的特征数量为止。

RFECV在一个交叉验证的循环中执行 RFE 来找到最优的特征数量。

示例
递归特征消除: 数字分类任务中像素相关性的递归特征消除实例.
带交叉验证的递归特征消除:一个自动调整交叉验证特征数的递归特征消除示例.

1.13.4 基于SelectFromModel的特征选择

SelectFromModel是一个元转换器(meta-transformer),它可以与任何具有 coef_属性或feature_importances_属性的估值器一起使用。如果相应的coef_feature_importances_低于所提供的阈值参数,则这些特征被视为不重要并被删除。除了指定在数值上的阈值外,还可以通过给定字符串参数来使用内置的启发式方法找到一个合适的阈值。可用的启发式方法是“mean”, “median” 和浮点倍数,如 “0.1*mean”。结合阈值标准,可以使用max_features参数来设置要选择的特征数量的限制。

关于如何使用它的例子,请参阅下面的章节。

示例
使用SelectFromModel和LassoCV进行特征选择: 从 Boston 数据中自动选择最重要两个特征而不需要提前得知这一信息。

1.13.4.1 基于L1的特征选择

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

>>> 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
(1504)
>>> 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
(1503)

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

示例
基于稀疏特征的文本文档分类: 基于L1特征选择的文档分类算法比较.

L1-recovery和压缩感知

当选择了正确的 alpha 值以后, Lasso 可以仅通过少量观察点便恢复完整的非零特征, 假设特定的条件可以被满足的话。特别的,数据量需要 “足够大” ,不然 L1 模型的表现将随机。 “足够大” 的定义取决于非零系数的个数、特征数量的对数值、噪音的数量、非零系数的最小绝对值、 以及设计矩阵(design maxtrix) X 的结构。此外, 特征矩阵必须表现出特定的性质,如数据不能太相关。

对于非零系数的恢复, 如何选择 alpha 值没有通用的规则。alpha 值可以通过交叉验证来确定( LassoCV 或者 LassoLarsCV ),尽管这可能会导致欠惩罚(under-penalized)的模型:包括少量的无关变量对于预测值来说并非致命的。相反的, BIC( LassoLarsIC )倾向于给定高的 alpha 值。

参考文献 Richard G. Baraniuk “Compressive Sensing”, IEEE Signal Processing Magazine [120] July 2007 http://dsp.rice.edu/sites/dsp.rice.edu/files/cs/baraniukCSlecture07.pdf

1.13.4.2 基于树的特征选择

基于树的估计器(参看 sklearn.tree 模块和在 sklearn.ensemble 模块中的树的森林) 可以用来计算基于不存度的特征重要性,然后可以消除不相关的特征(当与 sklearn.feature_selection.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
(1504)
>>> 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               
(1502)
示例
树森林的特征重要性: 在合成数据上恢复有用特征的示例。
基于平行树的森林的像素重要性: 在人脸识别数据上的示例。

1.13.5 特征选择作为pipeline一部分

特征选择通常在实际的学习之前用来做预处理。在 scikit-learn 中推荐的方式是使用 :sklearn.pipeline.Pipeline:

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

在这段代码中,我们利用 sklearn.svm.LinearSVCsklearn.feature_selection.SelectFromModel 来评估特征的重要性并且选择出最相关的特征。 然后,在转化后的输出中使用一个 sklearn.ensemble.RandomForestClassifier 分类器,比如只使用相关的特征。你也可以使用其他特征选择的方法和可以提供评估特征重要性的分类器来执行相似的操作。 请查阅 sklearn.pipeline.Pipeline 来了解更多的实例。