在知乎上看到大佬特征工程的文章,摸着看了下,不懂的又东摸西查整合了一下,做一个知识备份(缝合怪)。
1.0 前言
当数据预处理完成后,我们需要选择有意义的特征输入机器学习的算法和模型进行训练。通常来说,从两个方面考虑来选择特征:
1.特征是否发散:如果不发散,比如特征方差接近0,样本在这个特征上没什么差异
2.特征与目标的相关性
根据特征选择的形式又可以将特征选择方法分为3种:
1.Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
2.Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
3.Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数, 根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。
本文将使用sklearn中的feature_selection库来进行特征选择。
1.1 Filter
1.1.1 方差选择法
VarianceThreshold将计算各个特征的方差,并删除低方差的特征。
VarianceThreshold只关注输入X,而不在意Y,所以可以用于无监督学习。
from sklearn.feature_selection import VarianceThreshold
>>> X = [[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]]
>>> selector = VarianceThreshold()
# fit_transform将返回特征选择后的参数
>>> selector.fit_transform(X)
array([[2, 0],
[1, 4],
[1, 1]])
可以在参数中设定threshold阈值来选择特征。
1.1.2 相关系数法
SelectKBest将根据k个最高分来选择特征。pearsonr可以计算特征与目标变量之间的相关度,p值越小,表示相关系数越显著。可以结合计算各个特征对目标值的相关系数以及相关系数的P值。
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#选择K个最好的特征,返回选择特征后的数据
#第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,
输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
#k为选择的特征数
SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
sklearn给出的示例:
>>> from sklearn.datasets import load_digits
>>> from sklearn.feature_selection import SelectKBest, chi2
>>> X, y = load_digits(return_X_y=True)
>>> X.shape
(1797, 64)
>>> X_new = SelectKBest(chi2, k=20).fit_transform(X, y)
>>> X_new.shape
(1797, 20)
1.1.3 卡方检验
卡方检验是检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i、且因变量等于j的样本频数的观察值与期望的差距,构建统计量:
$X^2=\int{\frac{(A-E)^2}{E}$
这个统计量能计算自变量对因变量的相关性。
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#选择K个最好的特征,返回选择特征后的数据
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)
1.1.4 互信息法
互信息也可以用于评价定性自变量对定性因变量的相关性。MIC最大信息系数将计算最大互信息值,并对最大的互信息值进行归一化(除以log(min(X, Y))),再选择不同尺度下互信息的最大值作为MIC值。
Python中的minepy类库中实现了MIC算法。
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由于MINE的设计不是函数式的,定义mic方法将其为函数式的,返回一个二元组,二元组的第2项设置成固定的P值0.5
def mic(x, y):
m = MINE()
m.compute_score(x, y)
return (m.mic(), 0.5)
#选择K个最好的特征,返回特征选择后的数据
SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
1.2 Wrapper
1.2.1 递归特征消除法
递归消除特征将选择一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练。在sklearn实现了的包裹式(wrapper)特征选取只有两个递归式特征消除的方法,RFE和RFECV。
sklearn中的recursive feature elimination ( RFE )通过学习器返回的 coef_ 属性 或者 feature_importances_ 属性来获得每个特征的重要程度,然后,从当前的特征集合中移除最不重要的特征。在特征集合上不断的重复递归这个步骤,直到最终达到所需要的特征数量为止。
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#递归特征消除法,返回特征选择后的数据
#参数estimator为基模型
#参数n_features_to_select为选择的特征个数
RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)
sklearn还提供了RFECV,通过交叉验证来找到最优的特征数量。使用交叉验证来保留最佳性能的特征。在REF的基础上对不同的特征组合进行交叉验证,学习器本身不变,通过计算其决策系数之和,最终得到不同特征对于score的重要程度,然后保留最佳的特征组合。其分割方式类似于随机森林中的列上子采样。
(这个感觉,其实也可以自己查看feature_importances_,自己选)
RFECV还有两个缺陷,一,计算量大。二,随着学习器(评估器)的改变,最佳特征组合也会改变,有些时候会造成不利影响。
1.3 Embedded
1.3.1 基于惩罚项的特征选择法
使用带惩罚项的基模型,除了筛选出特征外,同时也进行了降维。使用feature_selection库的SelectFromModel类结合带L1惩罚项的逻辑回归模型,来选择特征的代码如下:
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带L1惩罚项的逻辑回归作为基模型的特征选择
SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)
1.3.2 基于树模型的特征选择法
树模型中GBDT也可用来作为基模型进行特征选择,使用feature_selection库的SelectFromModel类结合GBDT模型,来选择特征的代码如下:
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT作为基模型的特征选择
SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data, iris.target)
1.4 回顾
类 | 所属方式 | 说明 |
---|---|---|
VarianceThreshold | Filter | 按方差选择特征 |
SelectKBest | Filter | 结合关联系数、卡方校验、最大信息系数来做得分计算 |
RFE | Wrapper | 递归地训练基模型,将权值系数较小的特征从特征集合中消除 |
RFEV | Wrapper | 在REF的基础上对不同的特征组合进行交叉验证,然后保留最佳的特征组合 |
SelectFromModel | Embedded | 训练基模型,选择权值系数较高的特征 |
References
递归式特征消除:Recursive feature elimination
sklearn.feature_selection.VarianceThreshold