14.md 16.3 KB
Newer Older
L
loopyme 已提交
1
# 1.13. 特征选择
W
init  
wizardforcel 已提交
2 3 4 5

校验者:
        [@yuezhao9210](https://github.com/yuezhao9210)
        [@BWM-蜜蜂](https://github.com/apachecn/scikit-learn-doc-zh)
L
loopyme 已提交
6
        [@Loopy](https://github.com/loopyme)
W
init  
wizardforcel 已提交
7 8 9 10 11
翻译者:
        [@v](https://github.com/apachecn/scikit-learn-doc-zh)

[`sklearn.feature_selection`](classes.html#module-sklearn.feature_selection "sklearn.feature_selection") 模块中的类可以用来对样本集进行 feature selection(特征选择)和 dimensionality reduction(降维),这将会提高估计器的准确度或者增强它们在高维数据集上的性能。

L
loopyme 已提交
12
## 1.13.1. 移除低方差特征
W
init  
wizardforcel 已提交
13

14
[`VarianceThreshold`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.VarianceThreshold.html#sklearn.feature_selection.VarianceThreshold "sklearn.feature_selection.VarianceThreshold") 是特征选择的一个简单基本方法,它会移除所有那些方差不满足一些阈值的特征。默认情况下,它将会移除所有的零方差特征,即那些在所有的样本上的取值均不变的特征。
W
init  
wizardforcel 已提交
15 16 17 18 19 20 21 22 23 24 25 26 27

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

![\mathrm{Var}[X] = p(1 - p)](img/468283fb7514d3373112cb7db7c43356.jpg)

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

```py
>>> 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],
L
loopyme 已提交
28 29 30 31 32
       [1, 0],
       [0, 0],
       [1, 1],
       [1, 0],
       [1, 1]])
W
init  
wizardforcel 已提交
33 34 35 36 37

```

正如预期一样, `VarianceThreshold` 移除了第一列,它的值为 0 的概率为 ![p = 5/6 > .8](img/dc219bfd2e157456e106676575955251.jpg) 。

L
loopyme 已提交
38
## 1.13.2. 单变量特征选择
W
init  
wizardforcel 已提交
39 40 41

单变量的特征选择是通过基于单变量的统计测试来选择最好的特征。它可以当做是评估器的预处理步骤。Scikit-learn 将特征选择的内容作为实现了 transform 方法的对象:

L
loopyme 已提交
42 43 44 45
*   [`SelectKBest`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectKBest.html#sklearn.feature_selection.SelectKBest "sklearn.feature_selection.SelectKBest") 移除那些除了评分最高的 K 个特征之外的所有特征
*   [`SelectPercentile`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectPercentile.html#sklearn.feature_selection.SelectPercentile "sklearn.feature_selection.SelectPercentile") 移除除了用户指定的最高得分百分比之外的所有特征
*   对每个特征应用常见的单变量统计测试: 假阳性率(false positive rate) [`SelectFpr`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectFpr.html#sklearn.feature_selection.SelectFpr "sklearn.feature_selection.SelectFpr"), 伪发现率(false discovery rate) [`SelectFdr`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectFdr.html#sklearn.feature_selection.SelectFdr "sklearn.feature_selection.SelectFdr") , 或者族系误差(family wise error) [`SelectFwe`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectFwe.html#sklearn.feature_selection.SelectFwe "sklearn.feature_selection.SelectFwe") 。
*   [`GenericUnivariateSelect`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.GenericUnivariateSelect.html#sklearn.feature_selection.GenericUnivariateSelect "sklearn.feature_selection.GenericUnivariateSelect") 允许使用可配置方法来进行单变量特征选择。它允许超参数搜索评估器来选择最好的单变量特征。
W
init  
wizardforcel 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

例如下面的实例,我们可以使用 ![\chi^2](img/c019126f38fb92a868a7155bd707a5f8.jpg) 检验样本集来选择最好的两个特征:

```py
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import chi2
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
>>> X_new.shape
(150, 2)

```

63
这些对象将得分函数作为输入,返回单变量的得分和 p 值 (或者仅仅是 [`SelectKBest`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectKBest.html#sklearn.feature_selection.SelectKBest "sklearn.feature_selection.SelectKBest") 和 [`SelectPercentile`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectPercentile.html#sklearn.feature_selection.SelectPercentile "sklearn.feature_selection.SelectPercentile") 的分数):
W
init  
wizardforcel 已提交
64

L
loopyme 已提交
65 66
*   对于回归: [`f_regression`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.f_regression.html#sklearn.feature_selection.f_regression "sklearn.feature_selection.f_regression") , [`mutual_info_regression`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.mutual_info_regression.html#sklearn.feature_selection.mutual_info_regression "sklearn.feature_selection.mutual_info_regression")
*   对于分类: [`chi2`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.chi2.html#sklearn.feature_selection.chi2 "sklearn.feature_selection.chi2") , [`f_classif`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.f_classif.html#sklearn.feature_selection.f_classif "sklearn.feature_selection.f_classif") , [`mutual_info_classif`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.mutual_info_classif.html#sklearn.feature_selection.mutual_info_classif "sklearn.feature_selection.mutual_info_classif")
W
init  
wizardforcel 已提交
67 68 69

这些基于 F-test 的方法计算两个随机变量之间的线性相关程度。另一方面,mutual information methods(互信息)能够计算任何种类的统计相关性,但是作为非参数的方法,互信息需要更多的样本来进行准确的估计。

L
loopyme 已提交
70 71 72
>**稀疏数据的特征选择**
>
>如果你使用的是稀疏的数据 (例如数据可以由稀疏矩阵来表示),[`chi2`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.chi2.html#sklearn.feature_selection.chi2 "sklearn.feature_selection.chi2") , [`mutual_info_regression`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.mutual_info_regression.html#sklearn.feature_selection.mutual_info_regression "sklearn.feature_selection.mutual_info_regression") , [`mutual_info_classif`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.mutual_info_classif.html#sklearn.feature_selection.mutual_info_classif "sklearn.feature_selection.mutual_info_classif") 可以处理数据并保持它的稀疏性。
W
init  
wizardforcel 已提交
73

L
loopyme 已提交
74 75 76
>**警告**
>
>不要使用一个回归评分函数来处理分类问题,你会得到无用的结果。
W
init  
wizardforcel 已提交
77

L
loopyme 已提交
78 79 80
>**示例:**
>*   [Univariate Feature Selection](https://scikit-learn.org/stable/auto_examples/feature_selection/plot_feature_selection.html#sphx-glr-auto-examples-feature-selection-plot-feature-selection-py)
>*   [Comparison of F-test and mutual information](https://scikit-learn.org/stable/auto_examples/feature_selection/plot_f_test_vs_mi.html#sphx-glr-auto-examples-feature-selection-plot-f-test-vs-mi-py)
W
init  
wizardforcel 已提交
81

L
loopyme 已提交
82
## 1.13.3. 递归式特征消除
W
init  
wizardforcel 已提交
83

84
给定一个外部的估计器,可以对特征赋予一定的权重(比如,线性模型的相关系数),recursive feature elimination ( [`RFE`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.RFE.html#sklearn.feature_selection.RFE "sklearn.feature_selection.RFE") ) 通过考虑越来越小的特征集合来递归的选择特征。 首先,评估器在初始的特征集合上面训练并且每一个特征的重要程度是通过一个 `coef_` 属性 或者 `feature_importances_` 属性来获得。 然后,从当前的特征集合中移除最不重要的特征。在特征集合上不断的重复递归这个步骤,直到最终达到所需要的特征数量为止。 [`RFECV`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.RFECV.html#sklearn.feature_selection.RFECV "sklearn.feature_selection.RFECV") 在一个交叉验证的循环中执行 RFE 来找到最优的特征数量
W
init  
wizardforcel 已提交
85

L
loopyme 已提交
86
>**示例:**
片刻小哥哥's avatar
片刻小哥哥 已提交
87
>*   [Recursive feature elimination](https://scikit-learn.org/stable/auto_examples/feature_selection/plot_rfe_digits.html#sphx-glr-auto-examples-feature-selection-plot-rfe-digits-py) : 通过递归式特征消除来体现数字分类任务中像素重要性的示例。
L
loopyme 已提交
88
>*   [Recursive feature elimination with cross-validation](https://scikit-learn.org/stable/auto_examples/feature_selection/plot_rfe_with_cross_validation.html#sphx-glr-auto-examples-feature-selection-plot-rfe-with-cross-validation-py) : 通过递归式特征消除来自动调整交叉验证中选择的特征数。
W
init  
wizardforcel 已提交
89

L
loopyme 已提交
90
## 1.13.4. 使用 SelectFromModel 选取特征
W
init  
wizardforcel 已提交
91

92
[`SelectFromModel`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectFromModel.html#sklearn.feature_selection.SelectFromModel "sklearn.feature_selection.SelectFromModel") 是一个 meta-transformer(元转换器) ,它可以用来处理任何带有 `coef_` 或者 `feature_importances_` 属性的训练之后的评估器。 如果相关的``coef_`` 或者 `featureimportances` 属性值低于预先设置的阈值,这些特征将会被认为不重要并且移除掉。除了指定数值上的阈值之外,还可以通过给定字符串参数来使用内置的启发式方法找到一个合适的阈值。可以使用的启发式方法有 mean 、 median 以及使用浮点数乘以这些(例如,0.1*mean )。
W
init  
wizardforcel 已提交
93

片刻小哥哥's avatar
片刻小哥哥 已提交
94
有关如何使用的示例,可以参阅下面的示例。
W
init  
wizardforcel 已提交
95

L
loopyme 已提交
96 97
>**示例:**
>*  [Feature selection using SelectFromModel and LassoCV](https://scikit-learn.org/stable/auto_examples/feature_selection/plot_select_from_model_boston.html#sphx-glr-auto-examples-feature-selection-plot-select-from-model-boston-py): 从 Boston 数据中自动选择最重要两个特征而不需要提前得知这一信息。
W
init  
wizardforcel 已提交
98

L
loopyme 已提交
99
### 1.13.4.1. 基于 L1 的特征选取
W
init  
wizardforcel 已提交
100

L
loopyme 已提交
101
[Linear models](/docs/2) 使用 L1 正则化的线性模型会得到稀疏解:他们的许多系数为 0。 当目标是降低使用另一个分类器的数据集的维度, 它们可以与 [`feature_selection.SelectFromModel`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectFromModel.html#sklearn.feature_selection.SelectFromModel "sklearn.feature_selection.SelectFromModel") 一起使用来选择非零系数。特别的,可以用于此目的的稀疏评估器有用于回归的 [`linear_model.Lasso`](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html#sklearn.linear_model.Lasso "sklearn.linear_model.Lasso") , 以及用于分类的 [`linear_model.LogisticRegression`](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression "sklearn.linear_model.LogisticRegression") 和 [`svm.LinearSVC`](https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC "sklearn.svm.LinearSVC")
W
init  
wizardforcel 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

```py
>>> from sklearn.svm import LinearSVC
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> 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 的值越大,越少的特征会被选择。

L
loopyme 已提交
121 122
>**示例:**
>*   [Classification of text documents using sparse features](https://scikit-learn.org/stable/auto_examples/text/document_classification_20newsgroups.html#sphx-glr-auto-examples-text-document-classification-20newsgroups-py): 不同算法的比较,当使用 L1 正则化的特征选择在文件分类任务上。
W
init  
wizardforcel 已提交
123

L
loopyme 已提交
124 125 126 127 128 129 130
>**L1-recovery 和 compressive sensing(压缩感知)**
>
>当选择了正确的 alpha 值以后, [Lasso](linear_model.html#lasso) 可以仅通过少量观察点便恢复完整的非零特征, 假设特定的条件可以被满足的话。特别的,数据量需要 “足够大” ,不然 L1 模型的表现将缺乏保障。 “足够大” 的定义取决于非零系数的个数、特征数量的对数值、噪音的数量、非零系数的最小绝对值、 以及设计矩阵(design maxtrix) X 的结构。特征矩阵必须有特定的性质,如数据不能过度相关。
>
>关于如何选择 alpha 值没有固定的规则。alpha 值可以通过交叉验证来确定( `LassoCV` 或者 `LassoLarsCV` ),尽管这可能会导致欠惩罚的模型:包括少量的无关变量对于预测值来说并非致命的。相反的, BIC( `LassoLarsIC` )倾向于给定高 alpha 值。
>
>**Reference(参考文献)** Richard G. Baraniuk “Compressive Sensing”, IEEE Signal Processing Magazine [120] July 2007 [http://dsp.rice.edu/sites/dsp.rice.edu/files/cs/baraniukCSlecture07.pdf](http://dsp.rice.edu/sites/dsp.rice.edu/files/cs/baraniukCSlecture07.pdf)
W
init  
wizardforcel 已提交
131

L
loopyme 已提交
132
### 1.13.4.2. 基于 Tree(树)的特征选取
W
init  
wizardforcel 已提交
133

L
loopyme 已提交
134
基于树的 estimators (查阅 [`sklearn.tree`](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.tree) 模块和树的森林 在 [`sklearn.ensemble`](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.ensemble) 模块) 可以用来计算特征的重要性,然后可以消除不相关的特征(当与 [`sklearn.feature_selection.SelectFromModel`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectFromModel.html#sklearn.feature_selection.SelectFromModel "sklearn.feature_selection.SelectFromModel") 等元转换器一同使用时):
W
init  
wizardforcel 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

```py
>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> clf = ExtraTreesClassifier()
>>> 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)

```

L
loopyme 已提交
155 156 157
>**示例:**
>*   [Feature importances with forests of trees](https://scikit-learn.org/stable/auto_examples/ensemble/plot_forest_importances.html#sphx-glr-auto-examples-ensemble-plot-forest-importances-py): 在合成数据上恢复有用特征的示例。
>*   [Pixel importances with a parallel forest of trees](https://scikit-learn.org/stable/auto_examples/ensemble/plot_forest_importances_faces.html#sphx-glr-auto-examples-ensemble-plot-forest-importances-faces-py): 在人脸识别数据上的示例。
W
init  
wizardforcel 已提交
158

L
loopyme 已提交
159
## 1.13.5. 特征选取作为 pipeline(管道)的一部分
W
init  
wizardforcel 已提交
160

161
特征选择通常在实际的学习之前用来做预处理。在 scikit-learn 中推荐的方式是使用 :[`sklearn.pipeline.Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline"):
W
init  
wizardforcel 已提交
162 163 164 165 166 167 168 169 170 171

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

```

L
loopyme 已提交
172
在这段代码中,我们利用 [`sklearn.svm.LinearSVC`](https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC "sklearn.svm.LinearSVC") 和 [`sklearn.feature_selection.SelectFromModel`](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectFromModel.html#sklearn.feature_selection.SelectFromModel "sklearn.feature_selection.SelectFromModel") 来评估特征的重要性并且选择出相关的特征。 然后,在转化后的输出中使用一个 [`sklearn.ensemble.RandomForestClassifier`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html#sklearn.ensemble.RandomForestClassifier "sklearn.ensemble.RandomForestClassifier") 分类器,比如只使用相关的特征。你也可以使用其他特征选择的方法和可以提供评估特征重要性的分类器来执行相似的操作。 请查阅 [`sklearn.pipeline.Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 来了解更多的实例。