Feature Engineering, 称之为特征工程,属于机器学习中数据预处理阶段的重要内容,细分为以下两大类内容
1. Feature Extraction, 特征提取,从文本,图像等原始数据中提取可以用于建模的特征
2. Feature Selection, 特征选择,从原始数据中的多维特征中筛选最优特征自己,达到降维,提升模型准确性,减少运行时间等效果
特征选择的策略可以分为以下3大类
1. Filter
根据某项指标的阈值对特征进行过滤,常见的有以下三种方法
1. 方差
2. 相关系数
3. 卡方检验
方差表征数据的发散程度,方差越大,数据分布越发散。对于分类数据而言,特征对应的数据分布越集中,对分类器的贡献越小,所以会删除方差较小的特征。在scikit-learn中,可以通过如下方式指定方差阈值,删除低方差对应的特征
>>> 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]])
相关系数表征两个连续性变量之间的线性相关性,比如经典的pearson相关系数,适用于两个服从高斯分布的连续变量,相关系数越接近0,两个变量的相关性越弱。对于回归类问题,可以根据自变量与因变量的相关性,去除相关系数低的特征。
卡方检验适用于两个离散型变量之间的关联程度,可以用于筛选分类问题中的离散自变量。
2. Wrapper
封装类的方法是将特征选择和机器学习模型合并到一起来考虑,通过迭代使用不同的特征组合来训练机器学习的模型,根据模型的效果来筛选对应的特征。根据迭代的方式,分为以下3类
1. 前向选择法,放入模型的特征依次增多,每次循环放入能最大限度提升模型效果的特征,直到任何特征都不能提升模型表现
2. 后向选择法,与前向选择法相反,第一次循环就放入所有特征,然后每次循环,剔除最不显著的特征,直到模型收敛
在实践中,最常用的是递归特征消除法,全称如下
recursive feature elimination
简称RFE,策略上属于后向选择,通过递归逐步减少特征来进行筛选。首先,采用所有特征进行训练,训练完成后每个特征对应一个权重,然后去掉权重最小的特征,用剩余的特征在进行训练,重复上述步骤,直到剩余的特征数量达到所需的特征数量。在scikit-learn中,使用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")
>>> selector = RFE(estimator, n_features_to_select=5, step=1)
>>> selector = selector.fit(X, y)
>>> selector.support_
array([ True, True, True, True, True, False, False, False, False,
False])
>>> selector.ranking_
array([1, 1, 1, 1, 1, 6, 4, 3, 2, 5])
在该算法中,需要人为指定所需的特征数量值。为了克服这个超参数的设置问题,scikit-learn中支持采用交叉验证的方式,对于特征的所有组合,计算所有组合的误差,选择误差最小的特征集合作为所挑选的特征,用法如下
>>> from sklearn.feature_selection import RFECV>>> from sklearn.svm import SVR
>>> X, y = make_friedman1(n_samples=50, n_features=10, random_state=0)
>>> estimator = SVR(kernel="linear")
>>> selector = RFECV(estimator, step=1, cv=5)
>>> selector = selector.fit(X, y)
>>> selector.support_
array([ True, True, True, True, True, False, False, False, False,
False])
>>> selector.ranking_
array([1, 1, 1, 1, 1, 6, 4, 3, 2, 5])
3. Embedding
嵌入式的策略也会用到机器学习的模型,但是和封装类不同的是,这里只训练一次,然后根据特征的权重直接进行筛选,所以速度更快。最常用的方法有以下两种
1. 基于正则项的模型
2. 基于随机森林的模型
以L1正则项为例,在其模型中会有很多系数为0的特征,我们可以通过筛选非零特征来进行特征筛选。在scikit-learn中,使用L1正则项来筛选特征的代码如下
>>> 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)
在随机森林模型中,可以将不纯度减少的平均值作为特征重要性的衡量指标,以此来筛选特征。随机森林由多颗决策树组成,决策树节点在分裂时,考虑的该特征对树的不纯度的减少程度,对于随机森林,计算的则是多颗树的平均值。在scikit-learn中,使用平均不纯度减少来筛选特征的代码如下
>>> 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)
对于机器学习而言,数据和特征决定了其上上限,模型和算法只是逼近这个上限而已。要掌握机器学习,除了经典的机器学习模型和算法,还需要对特征工程的相关策略进行了解和学习。
·end·
一个只分享干货的
生信公众号