详解数据预处理和特征工程-特征选择-Embedded嵌入法【菜菜的sklearn课堂笔记】

时间:2022-11-11 08:56:35

视频作者:菜菜TsaiTsai 链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili

嵌入法是一种让算法自己决定使用哪些特征的方法,即特征选择和算法训练同时进行。 在使用嵌入法时,我们先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据权值系数从大到小选择特征。 详解数据预处理和特征工程-特征选择-Embedded嵌入法【菜菜的sklearn课堂笔记】

权值系数往往代表了特征对于模型的某种贡献或某种重要性,比如决策树和树的集成模型中的feature_importances_属性,可以列出各个特征对树的建立的贡献,找出对模型建立最有用的特征。 相比于过滤法,嵌入法的结果会更加精确到模型的效用本身,对于提高模型效力有更好的效果。并且,由于考虑特征对模型的贡献,因此无关的特征(需要相关性过滤的特征)和无区分度的特征(需要方差过滤的特征)都会因为缺乏对模型的贡献而被删除掉,可谓是过滤法的进化版。

嵌入法也有明显的缺点。过滤法中使用的统计量可以使用统计知识和常识来查找范围(如p值应当低于显著性水平0.05),而嵌入法中使用的权值系数却没有这样的范围可找(我们可以说,权值系数为0的特征对模型丝毫没有作用),但当大量特征都对模型有贡献且贡献不一时,我们就很难去界定一个有效的临界值。例如对于1000个维度的数据来构建决策树,显然每个特征分到的feature_importances_会非常的小,我们不能说feature_importances_为0.01的特征贡献小,在高维度下,其有可能是feature_importances_中的最大值,因此显然不能用一个统一的阈值来一概而论 这种情况下,模型权值系数就是我们的超参数,我们或许需要学习曲线,或者根据模型本身的某些性质去判断这个超参数的最佳值究竟应该是多少。但是,学习曲线的速度本身就很慢。要注意的是,**嵌入法引入了算法来挑选特征,因此其计算速度也会和应用的算法有很大的关系。**如果采用计算量很大,计算缓慢的算法,嵌入法本身也会非常耗时耗力。并且,在选择完毕之后,我们还是需要自己来评估模型。 在我们之后的学习当中,每次讲解新的算法,我都会为大家提到这个算法中的特征工程是如何处理,包括具体到每个算法的嵌入法如何使用。

SelectFromModel(
    ['estimator', 'threshold=None', 'prefit=False', 'norm_order=1', 'max_features=None'],
)
# estimator:实例化的模型。只要是带feature_importances_或者coef_属性,或带有l1和l2惩罚项的模型都可以使用
# threshold:特征重要性的阈值,重要性低于这个阈值的特征都将被删除

以随机森林为例

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier as rfc
from sklearn.model_selection import cross_val_score

RFC_ = RFC(n_estimators=10,random_state=0)
X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y)
# 0.005是feature_importances_的阈值

X_embedded.shape
---
(42000, 47)

# 可以画学习曲线来找最佳阈值
import numpy as np
import matplotlib.pyplot as plt

threshold = np.linspace(0,(RFC_.fit(X,y).feature_importances_).max(),20)

score = []
for i in threshold:
	X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
	once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
	# 这就是所说的,在特征选择完毕之后,我们还是需要自己来评估模型表现
	score.append(once)
plt.plot(threshold,score)
plt.show()

详解数据预处理和特征工程-特征选择-Embedded嵌入法【菜菜的sklearn课堂笔记】

从图像上来看,随着阈值越来越高,模型的效果逐渐变差,被删除的特征越来越多,信息损失也逐渐变大。我们可以从中挑选一个数值来验证一下模型的效果。

X_embedded = SelectFromModel(RFC_,threshold=0.00067).fit_transform(X,y)
X_embedded.shape
---
(42000, 324)

cross_val_score(RFC_,X_embedded,y,cv=5).mean()
---
0.939905083368037

之前我们用方差过滤,选择保留一半特征,模型交叉验证的分数为0.9388098166696807,嵌入法高于这个分数且使用特征少于方差过滤,这是由于嵌入法比方差过滤更具体到模型的表现的缘故,换一个算法,使用同样的阈值,效果可能就没有这么好了

我们可以在第一条学习曲线后选定一个范围,使用细化的学习曲线来找到最佳值:

score2 = []
for i in np.linspace(0,0.00134,20):
	X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
	once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
	score2.append(once)
plt.figure(figsize=[20,5])
plt.plot(np.linspace(0,0.00134,20),score2)
plt.xticks(np.linspace(0,0.00134,20))
plt.show()

详解数据预处理和特征工程-特征选择-Embedded嵌入法【菜菜的sklearn课堂笔记】

查看结果,果然0.00067并不是最高点,真正的最高点0.000564已经将模型效果提升到了94%以上。我们使用0.000564来跑SelectFromModel,并且调整RFC的n_estimators来优化模型表现

X_embedded = SelectFromModel(RFC_,threshold=0.000564).fit_transform(X,y)
X_embedded.shape
---
(42000, 340)

cross_val_score(RFC_,X_embedded,y,cv=5).mean()
---
0.9408335415056387

cross_val_score(RFC(n_estimators=100,random_state=0),X_embedded,y,cv=5).mean()
---
0.9639525817795566

得出的特征数目依然小于方差筛选,并且模型的表现也比没有筛选之前更高,已经完全可以和计算一次半小时的KNN相匹敌(KNN的准确率是96.58%),接下来再对随机森林进行调参,准确率应该还可以再升高不少。 可见,在嵌入法下,我们很容易就能够实现特征选择的目标:减少计算量,提升模型表现。因此,比起要思考很多统计量的过滤法来说,嵌入法可能是更有效的一种方法。 然而,在算法本身很复杂的时候,过滤法的计算远远比嵌入法要快,所以大型数据中,我们还是会优先考虑过滤法