嵌入式特征选择是将特征选择过程与学习器训练过程融为一体,两者在同一个优化过程中完成,即在学习器训练过程中自动地进行了特征选择。
基于惩罚项的特征选择法
给定数据集 $D = {(x_1, y_1), (x_2, y_2), \cdots, (x_n, y_n)}$,其中 $x \in R^d, y \in R$。我们考虑最简单的线性回归模型,以平方误差为损失函数,则优化目标为
$$
min_w \sum_{i=1}^n(y_i - w^Tx_i)^2
$$
当样本特征很多,而样本数相对较少时,上式很容易陷入过拟合。为了缓解过拟合问题,可对上式引入正则化项。
- 使用 L2 范数正则化,则称为“岭回归”(ridge regression)。
$$
min_w \sum_{i=1}^n(y_i - w^Tx_i)^2 + \lambda ||w||_2^2
$$
通过引入 L2 范数正则化,确能显著降低过拟合的风险。
- 使用 L1 范数正则化,则称为 LASSO(Least Absolute Shrinkage and Selection Operator)。
$$
min_w \sum_{i=1}^n(y_i - w^Tx_i)^2 + \lambda ||w||_1
$$
L1 范数和 L2 范数正则化都有助于降低过拟合风险,但 L1 范数比 L2 范数更易于获得“稀疏”(sparse)解,即它求得的 w 会有更少的非零向量。
同时使用 L1 范数和 L2 范数,即可避免过拟合,同时也实现了降维,并筛选出相应的特征。
$$
min_w \sum_{i=1}^n(y_i - w^Tx_i)^2 + \lambda_1 ||w||_1 + \lambda_2||w||_2^2
$$
那么如何通过惩罚项来进行特征选择呢?对于回归问题,我们可以直接引入 Lasso,通过 Lasso 对数据集进行训练,挑选非零向量所对应的特征。
【代码实现】:Lasso 实现特征选择。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from sklearn.linear_model import Lasso from sklearn.datasets import load_boston
dataset_boston = load_boston() data_boston = dataset_boston.data target_boston = dataset_boston.target
model_lasso = Lasso() model_lasso.fit(data_boston, target_boston)
print(model_lasso.coef_)
array([-0.06343729, 0.04916467, -0. , 0. , -0. , 0.9498107 , 0.02090951, -0.66879 , 0.26420643, -0.01521159, -0.72296636, 0.00824703, -0.76111454])
|
然后使用 sklearn.feature_selection.SelectFromModel 方法来从模型中挑选特征子集。
1 2 3 4 5 6 7 8
| from sklearn.feature_selection import SelectFromModel model_sfm = SelectFromModel(model_lasso, prefit=True) print(model_sfm.transform(data_boston).shape)
(506, 10) print(data_boston.shape)
(506, 13)
|
可以看出,SelectFromModel 方法剔除了权值向量为零的特征。
那么对于分类问题该如何使用惩罚项来进行特征选择呢?
【代码实现】:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| from sklearn.linear_model import LogisticRegression
dataset_iris = load_iris() data_iris = dataset_iris.data target_iris = dataset_iris.target
model_lr = LogisticRegression(penalty='l1', C=0.01) model_lr.fit(data_iris, target_iris) print(model_lr.coef_)
array([[ 0. , 0. , -0.18016819, 0. ], [-0.03183986, 0. , 0. , 0. ], [-0.00677759, 0. , 0. , 0. ]])
model_lr2 = LogisticRegression() model_lr2.fit(data_iris, target_iris) print(model_lr2.coef_)
array([[ 0.41021713, 1.46416217, -2.26003266, -1.02103509], [ 0.4275087 , -1.61211605, 0.5758173 , -1.40617325], [-1.70751526, -1.53427768, 2.47096755, 2.55537041]])
model_sfm = SelectFromModel(model_lr, prefit=True) print(model_sfm.transform(data_iris).shape)
(150, 2) print(data_iris.shape)
(150, 4)
|
通过上述代码可以看到添加了 l1 惩罚项的逻辑回归模型能够对特征集做特征选择,并且在 SelectFromModel 方法的协助下挑选权值向量非零的特征。当然,我们也可以同时使用 l1 惩罚项和 l2 惩罚项,阅读本篇博客的各位可以自行实现。
除此之外,也可以使用 SVM 中的 LinearSVC 来实现分类问题的特征选择。
【代码实现】:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from sklearn.svm import LinearSVC
model_lsvc = LinearSVC(penalty='l1', C=0.01, dual=False) model_lsvc.fit(data_iris, target_iris) print(model_lsvc.coef_) array([[ 0. , 0.21702532, -0.28757517, 0. ], [ 0. , -0.09200224, 0. , 0. ], [-0.02505729, -0.18225482, 0.12929954, 0. ]]) model_sfm = SelectFromModel(model_lsvc, prefit=True) model_sfm.transform(data_iris).shape
(150, 3)
|
SVM 包中的 LinearSVR 则可以实现对回归问题的特征选择。
【重要】:对于 SVM 和逻辑回归,参数 C 控制稀疏程度,C 越小,被选中的特征也越少;对于 Lasso,参数 alpha 越大,被选中的特征越少。
基于树模型的特征选择法
决策树可用于特征选择,树节点的划分特征所组成的集合就是选择出的特征子集。先演示决策树模型计算特征的重要度,然后再演示森林模型计算特征的重要度。
由于树模型即可用于分类问题,又可用于回归问题,因此数据集我们选择波士顿房价数据集以及鸢尾花数据集,先演示回归问题,后演示分类问题。
1 2
| from sklearn.datasets import load_boston from sklearn.datasets import load_iris
|
树模型-回归问题
树模型算法选用 CART,这样既可以处理连续型数据,也可以处理离散型数据,同时以基尼系数作为特征选择标准。
【实现代码】:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from sklearn.tree import DecisionTreeRegressor
dataset_boston = load_boston() data_boston = dataset_boston.data target_boston = dataset_boston.target model_dtc = DecisionTreeRegressor() model_dtc.fit(data_boston, target_boston)
np.set_printoptions(precision=3) print(model_dtc.feature_importances_)
array([5.070e-02, 1.071e-03, 4.064e-03, 1.090e-03, 5.009e-02, 5.758e-01, 1.433e-02, 7.363e-02, 3.362e-04, 1.257e-02, 7.155e-03, 1.413e-02, 1.950e-01])
|
我们可以使用 sklearn.feature_selection.SelectFromModel 方法来从模型中挑选特征子集。
1 2 3 4 5 6 7 8 9 10 11 12 13
| from sklearn.feature_selection import SelectFromModel
model_sfm = SelectFromModel(model_dtc, prefit=True) print(model_sfm.transform(data_boston))
array([[6.575, 4.98 ], [6.421, 9.14 ], [7.185, 4.03 ], ..., [6.976, 5.64 ], [6.794, 6.48 ], [6.03 , 7.88 ]])
|
SelectFromModel 能够用于拟合后拥有 coef_ 或 feature_importance 属性的模型。如果特征对应的 coef_ 或 feature_importances_ 值低于设定的阈值 threshold,那么这些特征将被移除。关于 SelectFromModel 的更多介绍和用法请参考官方文档 传送门
森林模型-回归问题
常见的森林模型有随机森林模型以及极端森林模型,在此分别演示这两种模型对回归问题特征选择的作用。
【代码实现】:随机森林
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| from sklearn.ensemble import RandomForestRegressor
model_rfr = RandomForestRegressor(n_estimators=50) model_rfr.fit(data_boston, target_boston) print(model_rfr.feature_importances_)
array([0.036, 0.001, 0.005, 0.001, 0.024, 0.396, 0.017, 0.063, 0.003, 0.016, 0.016, 0.013, 0.409])
model_sfm = SelectFromModel(model_rfr, prefit=True) print(model_sfm.transform(data_boston))
array([[6.575, 4.98 ], [6.421, 9.14 ], [7.185, 4.03 ], ..., [6.976, 5.64 ], [6.794, 6.48 ], [6.03 , 7.88 ]])
|
【代码实现】:极端森林
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| from sklearn.ensemble import ExtraTreesRegressor
model_etr = ExtraTreesRegressor(n_estimators=50) model_etr.fit(data_boston, target_boston) print(model_etr.feature_importances_)
array([0.034, 0.004, 0.052, 0.016, 0.039, 0.326, 0.02 , 0.029, 0.017, 0.044, 0.056, 0.02 , 0.342]) model_sfm = SelectFromModel(model_etr, prefit=True) print(model_sfm.transform(data_boston))
array([[6.575, 4.98 ], [6.421, 9.14 ], [7.185, 4.03 ], ..., [6.976, 5.64 ], [6.794, 6.48 ], [6.03 , 7.88 ]])
|
树模型-分类问题
树模型的分类问题,处理方式与树模型的回归问题相同,区别就在于调用不同的树模型方法(从 DecisionTreeRegressor 转换为 DecisionTreeClassifier),其他操作都相同。
【代码实现】:
1 2 3 4 5 6 7 8 9 10 11 12
| from sklearn.tree import DecisionTreeClassifier
dataset_iris = load_iris() data_iris = dataset_iris.data target_iris = dataset_iris.target
model_dtc = DecisionTreeClassifier() model_dtc.fit(data_iris, target_iris) print(model_dtc.feature_importances_)
array([0.027, 0. , 0.051, 0.923])
|
森林模型-分类问题
【代码实现】:
1 2 3 4 5 6 7 8 9 10 11
| model_etc = ExtraTreesClassifier(n_estimators=50) model_etc.fit(data_iris, target_iris) print(model_etc.feature_importances_
array([0.06393643, 0.04529532, 0.39042913, 0.50033912])
model_rfc = RandomForestClassifier(n_estimators=50) model_rfc.fit(data_iris, target_iris) print(model_rfc.feature_importances_)
array([0.07155676, 0.01874959, 0.47878474, 0.43090891])
|
虽然不同模型输出的特征重要程度值不同,但特征的排序(按重要程度降序排列)是一致的。
参考