1.13. 特征选择#
模块 sklearn.feature_selection
中的类可用于对样本集进行特征选择/降维,以提高估计器的准确率得分,或提升其在高维数据集上的性能。
1.13.1. 移除低方差特征#
VarianceThreshold
是一种简单的特征选择基线方法。它会移除所有方差不满足某个阈值的特征。默认情况下,它会移除所有零方差特征,即在所有样本中值都相同的特征。
例如,假设我们有一个包含布尔特征的数据集,我们希望移除在超过 80% 的样本中其值为一或零(开或关)的所有特征。布尔特征是伯努利随机变量,此类变量的方差由以下公式给出:
因此我们可以使用阈值 .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 值(或仅返回 SelectKBest
和 SelectPercentile
的得分)
基于 F 检验的方法估计两个随机变量之间的线性依赖程度。另一方面,互信息方法可以捕获任何类型的统计依赖,但由于是非参数的,它们需要更多样本才能进行准确估计。请注意,\(\chi^2\) 检验只应应用于非负特征,例如频率。
警告
注意不要将回归评分函数用于分类问题,否则会得到无用的结果。
注意
SelectPercentile
和 SelectKBest
也支持无监督特征选择。需要提供一个 score_func
,其中 y=None
。score_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
,以及用于分类的 LogisticRegression
和 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
(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 恢复和压缩感知#
如果 alpha 选择得当,Lasso 仅使用少量观测值就能完全恢复非零变量的精确集合,前提是满足某些特定条件。特别是,样本数量应“足够大”,否则 L1 模型将随机表现;其中“足够大”取决于非零系数的数量、特征数量的对数、噪声量、非零系数的最小绝对值以及设计矩阵 X 的结构。此外,设计矩阵必须显示某些特定属性,例如不能过于相关。关于使用 Lasso 进行稀疏信号恢复,请参阅压缩感知示例:压缩感知:使用 L1 先验(Lasso)进行层析成像重建。
选择用于恢复非零系数的 alpha 参数没有通用规则。可以通过交叉验证(LassoCV
或 LassoLarsCV
)进行设置,尽管这可能导致欠惩罚模型:包含少量不相关变量对预测得分无害。相反,BIC (LassoLarsIC
) 倾向于设置较高的 alpha 值。
参考文献
Richard G. Baraniuk “压缩感知”, IEEE Signal Processing Magazine [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)
示例
使用树森林的特征重要性:一个合成数据示例,展示了实际有意义特征的恢复。
置换重要性 vs. 随机森林特征重要性(MDI):一个示例,讨论了使用基于杂质的特征重要性作为特征相关性代理的注意事项。
1.13.5. 序列特征选择#
序列特征选择 [sfs](SFS)在 SequentialFeatureSelector
转换器中可用。SFS 可以是前向或后向的。
前向 SFS 是一种贪婪过程,它迭代地寻找要添加到已选特征集中的最佳新特征。具体来说,我们最初从零个特征开始,找到在仅使用这一个特征训练估计器时能最大化交叉验证得分的特征。一旦第一个特征被选中,我们通过向已选特征集中添加新特征来重复该过程。当达到 n_features_to_select
参数所确定的所需特征数量时,该过程停止。
后向 SFS 遵循相同的思想,但工作方向相反:我们不从零特征开始贪婪地添加特征,而是从所有特征开始贪婪地移除特征。参数 direction
控制是使用前向 SFS 还是后向 SFS。
序列特征选择的详细信息#
通常,前向选择和后向选择不会产生等效的结果。此外,根据所需的所选特征数量,其中一种方法可能比另一种快得多:如果我们有 10 个特征并要求选择 7 个特征,则前向选择需要执行 7 次迭代,而后向选择只需执行 3 次。
SFS 与 RFE
和 SelectFromModel
的不同之处在于它不要求底层模型公开 coef_
或 feature_importances_
属性。然而,与其它方法相比,它可能更慢,因为它需要评估更多的模型。例如,在后向选择中,使用 k 折交叉验证从 m
个特征到 m - 1
个特征的迭代需要拟合 m * k
个模型,而 RFE
只需要一次拟合,SelectFromModel
总是只进行一次拟合,不需要迭代。
参考文献
Ferri et al, 大规模特征选择技术的比较研究。
示例
1.13.6. 作为管道一部分的特征选择#
特征选择通常在实际学习之前作为预处理步骤使用。在 scikit-learn 中,推荐的做法是使用 Pipeline
。
clf = Pipeline([
('feature_selection', SelectFromModel(LinearSVC(penalty="l1"))),
('classification', RandomForestClassifier())
])
clf.fit(X, y)
在此代码片段中,我们利用 LinearSVC
结合 SelectFromModel
来评估特征重要性并选择最相关的特征。然后,在转换后的输出(即仅使用相关特征)上训练一个 RandomForestClassifier
。当然,您可以使用其他特征选择方法以及提供评估特征重要性方式的分类器执行类似的操作。有关更多详细信息,请参阅 Pipeline
示例。