如何进行特征选择
程序员文章站
2024-03-08 19:34:40
...
如何进行特征选择
特征选择对于数据科学家、机器学习从业者来说非常重要。好的特征选择能够提升模型的性能,更能帮助我们理解数据的特点、底层结构,这对进一步改善模型、算法都有着重要作用。
当数据预处理完成后,我们需要选择有意义的特征输入机器学习的算法和模型进行训练。通常来说,从两个方面考虑来选择特征:
-
特征是否发散:如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。 -
特征与目标的相关性:与目标相关性高的特征,应该优先选择。
特征选择的两个目的:
-
减少特征的数量,达到降维的效果,从而使模型的方法能力更强,降低过拟合的风险; -
增强对特征和特征值之间的理解。
根据特征选择的形式又可以将特征选择方法分为3种:
-
Filter(过滤法):按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。 -
Wrapper(包装法):根据目标函数(通常是预测效果),每次选择若干特征,或者排除若干特征。 -
Embedded(嵌入法):先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。
(一)Filter
1、移除低方差的特征
假设某特征的特征值只有0和1,并且在所有输入样本中,95%的实例的该特征取值都是1,那就可以认为这个特征作用不大。如果100%都是1,那这个特征就没意义了。当特征值都是离散型变量的时候这种方法才能用,如果是连续型变量,就需要将连续变量离散化之后才能用。而且实际当中,一般不太会有95%以上都取某个值的特征存在,所以这种方法虽然简单但是不太好用。可以把它作为特征选择的预处理,先去掉那些取值变化小的特征,然后再从接下来提到的的特征选择方法中选择合适的进行进一步的特征选择。
>>> 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]])
2、单变量特征选择
单变量特征选择的原理是分别单独的计算每个变量的某个统计指标,根据该指标来判断哪些指标重要,剔除那些不重要的指标。
-
对于分类问题(y离散),可采用:
卡方检验,f_classif, mutual_info_classif,互信息
-
对于回归问题(y连续),可采用:
皮尔森相关系数,f_regression, mutual_info_regression,最大信息系数
这种方法比较简单,易于运行,易于理解,通常对于理解数据有较好的效果(但对特征优化、提高泛化能力来说不一定有效)。
利用scikit-learn进行特征选择的部分函数:
-
SelectKBest 移除得分前 k 名以外的所有特征(取top k) -
SelectPercentile 移除得分在用户指定百分比以后的特征(取top k%) -
对每个特征使用通用的单变量统计检验: 假正率(false positive rate) SelectFpr, 伪发现率(false discovery rate) SelectFdr, 或族系误差率 SelectFwe. -
GenericUnivariateSelect 可以设置不同的策略来进行单变量特征选择。同时不同的选择策略也能够使用超参数寻优,从而让我们找到最佳的单变量特征选择策略。
(1)卡方(Chi2)检验
经典的卡方检验是检验定性自变量对定性因变量的相关性。卡方检验就是统计样本的实际观测值与理论推断值之间的偏离程度,实际观测值与理论推断值之间的偏离程度就决定卡方值的大小,卡方值越大,越不符合;卡方值越小,偏差越小,越趋于符合,若两个值完全相等时,卡方值就为0,表明理论值完全符合。计算过程如下:
比如,我们可以对样本进行一次chi2测试来选择最佳的两项特征:
>>>
from sklearn.datasetsimport
load_iris>>>from
sklearn.feature_selectionimport SelectKBest>>>from
sklearn.feature_selectionimport 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)
(2)皮尔森相关系数(Pearson Correlation)
皮尔森相关系数是一种最简单的,能帮助理解特征和因变量之间关系的方法。该方法衡量的是变量之间的线性相关性,结果的取值区间为[-1,1],-1表示完全的负相关,+1表示完全的正相关,0表示没有线性相关。
皮尔森相关系数速度快、易于计算,经常在拿到数据(经过清洗和特征提取之后的)之后第一时间就执行。Scipy的pearsonr方法能够同时计算相关系数 和p-value。
例如:
import numpyas
npfrom scipy.statsimport
pearsonrnp.random.seed(0)size=300x=
np.random.normal(0,1,
size)# pearsonr(x, y)的输入为特征矩阵和目标向量print(“Lower
noise”, pearsonr(x, x+
np.random.normal(0,1,
size)))print(“Higher noise”,
pearsonr(x, x+ np.random.normal(0,10,
size)))>>># 输出为二元组(sorce, p-value)的数组
#可以看出,当噪声比较小时,相关性很强,p-value比较小Lower noise (0.71824836862138386,7.3240173129992273e-49)Higher
noise (0.057964292079338148,0.31700993885324746)
缺点:作为特征排序机制,它只对线性关系敏感。如果关系是非线性的,即便两个变量具有一一对应的关系,Pearson相关性也可能会接近0。
(3)互信息和最大信息系数 (Mutual information and maximal information coefficient (MIC)
互信息(互信息为随机变量X与Y之间的互信息,互信息为0,代表X与Y是独立的)也是评价定性自变量与定性因变量的相关性的。
缺点:互信息直接用于特征选择其实不是太方便:1、它不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较;2、对于连续变量的计算不是很方便(X和Y都是集合,x,y都是离散的取值),通常变量需要先离散化,而互信息的结果对离散化的方式很敏感。
最大信息系数克服了这两个问题。它首先寻找一种最优的离散化方式,然后把互信息取值转换成一种度量方式,取值区间在[0,1]。 minepy 提供了MIC功能。
例如,y=x^2的例子。
from minepyimport
MINEm= MINE()x= np.random.uniform(-1,1,10000)m.compute_score(x,
x**2)print(m.mic())>>>1.0
(4)距离相关系数(Distance Correlation)
距离相关系数是为了克服Pearson相关系数的弱点而生的。在xx和x2x2这个例子中,即便Pearson相关系数是0,我们也不能断定这两个变量是独立的(有可能是非线性相关);但如果距离相关系数是0,那么我们就可以说这两个变量是独立的。
例如:
>x = runif
(1000, -1,1)
> dcor(x, x**2) [1]0.4943864
缺点:
尽管有 MIC 和 距离相关系数 在了,但当变量之间的关系接近线性相关的时候,Pearson相关系数仍然是不可替代的。
第一,Pearson相关系数计算速度快,这在处理大规模数据的时候很重要。
第二,Pearson相关系数的取值区间是[-1,1],而MIC和距离相关系数都是[0,1]。这个特点使得Pearson相关系数能够表征更丰富的关系,符号表示关系的正负,绝对值能够表示强度。当然,Pearson相关性有效的前提是两个变量的变化关系是单调的。
(5)基于模型的特征排序(Model based ranking)
这种方法的思路是直接使用你要用的机器学习算法,针对每个单独的特征 和响应变量建立预测模型。假如特征和响应变量之间的关系是非线性的,可以用基于树的方法(决策树、随机森林)或者扩展的线性模型等。基于树的方法比较易于使用,因为他们对非线性关系的建模比较好,并且不需要太多的调试。但要注意过拟合问题,因此树的深度最好不要太大,再就是运用交叉验证。
例如:
在 波士顿房价数据集 上使用sklearn的 随机森林回归 给出一个_单变量选择_的例子(这里使用了交叉验证):
from sklearn.cross_validationimport
cross_val_score, ShuffleSplitfrom sklearn.datasetsimport
load_bostonfrom sklearn.ensemble
import RandomForestRegressorimport
numpy as np# Load boston housing dataset as an exampleboston=
load_boston()X= boston[“data”]Y=
boston[“target”]names=
boston[“feature_names”]rf=
RandomForestRegressor(n_estimators=20, max_depth=4)scores=
[]# 单独采用每个特征进行建模,并进行交叉验证for
i inrange(X.shape[1]):
score= cross_val_score(rf, X[:, i:i+1], Y,
scoring=“r2”,# 注意X[:, i]和X[:, i:i+1]的区别
cv=ShuffleSplit(len(X),3,.3))
scores.append((format(np.mean(score),‘.3f’),
names[i]))print(sorted(scores, reverse=True))
结果:
[(‘0.620’, ‘LSTAT’), (‘0.591’, ‘RM’), (‘0.467’, ‘NOX’), (‘0.342’, ‘INDUS’), (‘0.305’, ‘TAX’), (‘0.240’, ‘PTRATIO’), (‘0.206’, ‘CRIM’), (‘0.187’, ‘RAD’), (‘0.184’, ‘ZN’), (‘0.135’, ‘B’), (‘0.082’, ‘DIS’), (‘0.020’, ‘CHAS’), (‘0.002’,
‘AGE’)]
(二)Wrapper
1、递归特征消除(Recursive Feature Elimination)
递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,移除若干权值系数的特征,再基于新的特征集进行下一轮训练。
sklearn官方解释:对特征含有权重的预测模型(例如,线性模型对应参数coefficients),RFE通过递归减少考察的特征集规模来选择特征。首先,预测模型在原始特征上训练,每个特征指定一个权重。之后,那些拥有最小绝对值权重的特征被踢出特征集。如此往复递归,直至剩余的特征数量达到所需的特征数量。
RFECV 通过交叉验证的方式执行RFE,以此来选择最佳数量的特征:对于一个数量为d的feature的集合,他的所有的子集的个数是2的d次方减1(包含空集)。指定一个外部的学习算法,比如SVM之类的。通过该算法计算所有子集的validation error。选择error最小的那个子集作为所挑选的特征。
from sklearn.feature_selectionimport
RFEfrom sklearn.linear_modelimport
LogisticRegression#递归特征消除法,返回特征选择后的数据#参数estimator为基模型#参数n_features_to_select为选择的特征个数RFE(estimator=LogisticRegression(),
n_features_to_select=2).fit_transform(iris.data, iris.target)
(三)Embedded
1、使用SelectFromModel选择特征 (Feature selection using SelectFromModel)
单变量特征选择方法独立的衡量每个特征与响应变量之间的关系,另一种主流的特征选择方法是基于机器学习模型的方法。有些机器学习方法本身就具有对特征进行打分的机制,或者很容易将其运用到特征选择任务中,例如回归模型,SVM,决策树,随机森林等等。其实Pearson相关系数等价于线性回归里的标准化回归系数。
SelectFromModel 作为meta-transformer,能够用于拟合后任何拥有coef_或feature_importances_ 属性的预测模型。如果特征对应的coef_ 或 feature_importances_ 值低于设定的阈值threshold,那么这些特征将被移除。除了手动设置阈值,也可通过字符串参数调用内置的启发式算法(heuristics)来设置阈值,包括:平均值(“mean”),
中位数(“median”)以及他们与浮点数的乘积,如”0.1*mean”。
(1)基于L1的特征选择(L1-based feature selection)
使用L1范数作为惩罚项的线性模型(Linear models)会得到稀疏解:大部分特征对应的系数为0。当你希望减少特征的维度以用于其它分类器时,可以通过 feature_selection.SelectFromModel 来选择不为0的系数。特别指出,常用于此目的的稀疏预测模型有 linear_model.Lasso(回归),
linear_model.LogisticRegression 和 svm.LinearSVC(分类):
>>> from sklearn.svmimport
LinearSVC>>>from sklearn.datasetsimport
load_iris>>>from sklearn.feature_selectionimport
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)
使用feature_selection库的SelectFromModel类结合带L1以及L2惩罚项的逻辑回归模型:
from sklearn.feature_selectionimport SelectFromModel#带L1和L2惩罚项的逻辑回归作为基模型的特征选择#参数threshold为权值系数之差的阈值SelectFromModel(LR(threshold=0.5,
C=0.1)).fit_transform(iris.data, iris.target)
对于SVM和逻辑回归,参数C控制稀疏性:C越小,被选中的特征越少。对于Lasso,参数alpha越大,被选中的特征越少。
(2)随机稀疏模型(Randomized sparse models)
基于L1的稀疏模型的局限在于,当面对一组互相关的特征时,它们只会选择其中一项特征。为了减轻该问题的影响可以使用随机化技术,通过_多次重新估计稀疏模型来扰乱设计矩阵_,或通过_多次下采样数据来统计一个给定的回归量被选中的次数_。
(3)基于树的特征选择
基于树的预测模型(见 sklearn.tree 模块,森林见 sklearn.ensemble 模块)能够用来计算特征的重要程度,因此能用来去除不相关的特征(结合 sklearn.feature_selection.SelectFromModel):
>>> from sklearn.ensembleimport
ExtraTreesClassifier>>>from sklearn.datasetsimport
load_iris>>>from sklearn.feature_selectionimport
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)
2、将特征选择过程融入pipeline (Feature selection as part of a pipeline)
特征选择常常被当作学习之前的一项预处理。在scikit-learn中推荐使用
sklearn.pipeline.Pipeline:
clf = Pipeline([ (‘feature_selection’, SelectFromModel(LinearSVC(penalty=“l1”))),
(‘classification’, RandomForestClassifier()) ])clf.fit(X, y)
(四)小结
(五)简短回答
常见的特征选择方式:
1、 去除方差较小的特征
2、正则化。1正则化能够生成稀疏的模型。L2正则化的表现更加稳定,由于有用的特征往往对应系数非零。
3、随机森林。对于分类问题,通常采用基尼不纯度或者信息增益,对于回归问题,通常采用的是方差或者最小二乘拟合。一般不需要feature engineering、调参等繁琐的步骤。它的两个主要问题,1是重要的特征有可能得分很低(关联特征问题),2是这种方法对特征变量类别多的特征越有利(偏向问题)。
4、 稳定性选择。是一种基于二次抽样和选择算法相结合较新的方法,选择算法可以是回归、SVM或其他类似的方法。它的主要思想是在不同的数据子集和特征子集上运行特征选择算法,不断的重复,最终汇总特征选择结果,比如可以统计某个特征被认为是重要特征的频率(被选为重要特征的次数除以它所在的子集被测试的次数)。理想情况下,重要特征的得分会接近100%。稍微弱一点的特征得分会是非0的数,而最无用的特征得分将会接近于0。
</div>
</div>