机器学习-->特征选择
这篇博文将详细介绍sklearn中特征选择的相关内容,全文部分翻译自sklearn.Feature selection,并且加上了我自己的一些见解。
特征选择主要有三种办法:
其中第一种过滤型很少使用。
特征选择思想简介
先大概讲讲上面三种方法思想:
过滤型
变量排序就是一种典型的过滤式方法,该方法独立于后续要使用的模型。这种方法的关键就是找到一种能度量特征重要性的方法,比如pearson相关系数,信息论理论中的互信息等。《机器学习》(Peter Flach)中还提到了卡方统计量,但未作详细介绍。变量排序方法的主要问题在于忽略了特征之间可能存在的相互依赖关系。一方面,即便排序靠前的特征,如果相关性较强,则引入了冗余的特征;另一方面,排序靠后的特征,虽然独立来看作用不明显,但可能与其它特征组合起来,就有很好的预测作用,如此就损失了有价值的特征。
其主要思想是:对每一维的特征“打分”,即给每一维的特征赋予权重,这样的权重就代表着该维特征的重要性,然后依据权重排序。
主要的方法有:
- Chi-squared test(卡方检验)
- information gain(信息增益),详细可见“简单易学的机器学习算法——决策树之ID3算法”
- correlation coefficient scores(相关系数)
包裹型
这类方法的核心思想在于,给定了某种模型,及预测效果评价的方法,然后针对特征空间中的不同子集,计算每个子集的预测效果,效果最好的,即作为最终被挑选出来的特征子集。注意集合的子集是一个指数的量级,故此类方法计算量较大。故而针对如何高效搜索特征空间子集,就产生了不同的算法。其中有一种简单有效的方法叫贪婪搜索策略,包括前向选择与后向删除。在前向选择方法中,初始化一个空的特征集合,逐步向其中添加新的特征,如果该特征能提高预测效果,即得以保留,否则就扔掉。后向删除即是说从所有特征构成的集合开始,逐步删除特征,只要删除后模型预测效果提升,即说明删除动作有效,否则就还是保留原特征。要注意到,包裹式方法要求针对每一个特征子集重新训练模型,因此计算量还是较大的。
嵌入式
嵌入式方法将特征选择融合在模型训练的过程中,比如决策树在分枝的过程中,就是使用的嵌入式特征选择方法,其内在还是根据某个度量指标对特征进行排序。
sklearn中是如何做特征选择
sklearn.feature_selection模块中的类可用于样本集上的特征选择/维数降低,以提高学习器的准确度或提高其在高维数据集上的性能。
去除低方差的特征(除去常变量特征)
VarianceThreshold是特征选择的简单准则方法。它删除方差不符合某个阈值的所有特征。默认情况下,它会删除所有零差异特征,即所有样本中具有相同值的特征。也就是除去常变量特征。
例如,假设我们有一个具有布尔特征的数据集,并且我们要删除超过80%的样本中的一个或零(开或关)的所有特征。布尔特征是伯努利随机变量,这些变量的方差由下式给出:
我们可以选择VarianceThreshold=.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,其方差约为0.1417<0.16,故去除。
过滤型
单变量特征选择(sklearn.feature_selection.SelectKBest)
通过选择基于单变量统计检验的最佳特征来进行单变量特征选择。它可以被看作是学习器的预处理步骤。 Scikit-learn将特征选择例程公开为实现变换方法的对象:
• SelectKBest 删除除最高得分特征外的所有特征
• SelectPercentile 删除除用户指定的最高得分百分比的其他所有特征
这允许使用超参数搜索估计器来选择最佳的单变量选择策略。
>>> 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)
下面对象将输入一个评分函数,返回单变量分数和p值(或仅用于SelectKBest和SelectPercentile的分数):
对于回归:f_regression, mutual_info_regression
对于分类:chi2, f_classif, mutual_info_classif
以上是一维一维的去评估特征对结果的影响。
稀疏数据中进行特征选择
如果使用稀疏数据(即表示为稀疏矩阵的数据),则chi2,mutual_info_regression,mutual_info_classif将处理数据而不使其变密。
包裹型
Recursive feature elimination(sklearn.feature_selection.RFE)
给定一个学习器,这个学习器会给每个特征赋予一定的权重,Recursive feature elimination(sklearn.feature_selection.RFE)是通过递归地考虑用越来越小的特征集来选择特征。首先,对初始的特征集进行训练,并将权重分配给它们中的每一个。然后,从当前设置的特征修剪绝对权重最小的特征。在修剪后的集合上递归地重复该过程,直到最终达到期望的要选择的特征数量。
RFECV在交叉验证循环中执行RFE以找到最佳数量的特征。
>>> from sklearn.datasets import make_friedman1
>>> from sklearn.feature_selection import RFE
>>> from sklearn.svm import SVR
>>> X, y = make_friedman1(n_samples=50, n_features=10, random_state=0)
>>> estimator = SVR(kernel="linear")
##5个特征被选中,每次迭代去除1个特征。
>>> selector = RFE(estimator, 5, step=1)
>>> selector = selector.fit(X, y)
>>> selector.support_ ##所选特征的掩码
array([ True, True, True, True, True,
False, False, False, False, False], dtype=bool)
##特征排名,使得rank_ [i]对应于第i个特征的排名位置。所选择的(即,估计的最佳)特征被分配为等级1。
>>> selector.ranking_
array([1, 1, 1, 1, 1, 6, 4, 3, 2, 5])
嵌入型
Feature selection using SelectFromModel
SelectFromModel是一个元变换器,可以与任何在fit后具有coef_或feature_importances_属性的学习器一起使用。如果相应的coef_或feature_importances_值低于提供的阈值参数,则这些特征被认为是不重要的并被移除。除了在数值上指定阈值之外,还有内置的启发式方法,用于使用字符串参数来查找阈值。可用的启发式是“平均值”,“中位数”和浮点倍数,如“0.1 * mean”。
L1-based feature selection
用L1范数惩罚的线性模型具有稀疏解:他们的许多估计系数为零。当目标是降低数据维度而与另一个分类器一起使用,它们可以与feature_selection.SelectFromModel一起使用以选择非零系数特征。特别地,SelectFromModel与linear_model.Lasso一起使用用于解决回归问题,与linear_model.LogisticRegression和svm.LinearSVC一起使用解决分类问题。
>>> 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,logistic-regression,参数c控制稀疏程度,参数c越小,越少的特征被选中。Lasso中,参数alpha越大越少的特征被选中。
Tree-based feature selection
基于树的学习器(参见sklearn.tree模块和sklearn.ensemble模块中的树的森林)可以用于计算特征重要性(feature_importances_),而后者又可用于丢弃不相关的特征(当与sklearn.feature_selection.SelectFromModel meta-transformer):
>>> 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)
另外一些特征选择方法
如果在训练数据中,某一个类别特征里面的属性取值较多,比如城市这个特征,里面可能有上海,北京,广州,深圳,南京,合肥,等等取值,那么这样直接做one-hot的话,维度会爆炸式增长。那这个时候应该怎么办呢?
对此应该根据具体的应用场景,挑选出一些对目标变量最具有影响性的属性取值。例如,在金融借贷场景中,我们可以选出违约率最高的几个城市,这里假设选出违约率最高的六个城市,那么可以构建六个二值特征,相当于对城市这个特征进行了独热编码。
但是有时候属性取值很多很多,比如达到上百个,这个时候可以用one-hot编码,那么就可以得出上百个维度的特征,然后在此基础上训练出一个基于树的模型,输出各个特征的重要度,提取出最重要的几个特征,然后再做二值特征。
同时也可以按照业务逻辑,对属性取值较多的类别特征进行区间的合并,比如划分合并成一线城市,二线城市等等。
上一篇: asp.net 常用字符串处理方法