机器学习实战基础(十七):sklearn中的数据预处理和特征工程(十)特征选择 之 Embedded嵌入法

时间:2023-03-09 07:59:45
机器学习实战基础(十七):sklearn中的数据预处理和特征工程(十)特征选择 之 Embedded嵌入法

Embedded嵌入法

嵌入法是一种让算法自己决定使用哪些特征的方法,即特征选择和算法训练同时进行。在使用嵌入法时,我们先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据权值系数从大到小选择特征。

这些权值系数往往代表了特征对于模型的某种贡献或某种重要性,比如决策树和树的集成模型中的feature_importances_属性,可以列出各个特征对树的建立的贡献,我们就可以基于这种贡献的评估,找出对模型建立最有用的特征。

因此相比于过滤法,嵌入法的结果会更加精确到模型的效用本身,对于提高模型效力有更好的效果。并且,由于考虑特征对模型的贡献,因此无关的特征(需要相关性过滤的特征)和无区分度的特征(需要方差过滤的特征)都会因为缺乏对模型的贡献而被删除掉,可谓是过滤法的进化版。

机器学习实战基础(十七):sklearn中的数据预处理和特征工程(十)特征选择 之 Embedded嵌入法

然而,嵌入法也不是没有缺点。

过滤法中使用的统计量可以使用统计知识和常识来查找范围(如p值应当低于显著性水平0.05),而嵌入法中使用的权值系数却没有这样的范围可找——我们可以说,权值系数为0的特征对模型丝毫没有作用,但当大量特征都对模型有贡献且贡献不一时,我们就很难去界定一个有效的临界值。

这种情况下,模型权值系数就是我们的超参数,我们或许需要学习曲线,或者根据模型本身的某些性质去判断这个超参数的最佳值究竟应该是多少。
在我们之后的学习当中,每次讲解新的算法,我都会为大家提到这个算法中的特征工程是如何处理,包括具体到每个算法的嵌入法如何使用。在这堂课中,我们会为大家讲解随机森林和决策树模型的嵌入法。

另外,嵌入法引入了算法来挑选特征,因此其计算速度也会和应用的算法有很大的关系。如果采用计算量很大,计算缓慢的算法,嵌入法本身也会非常耗时耗力。并且,在选择完毕之后,我们还是需要自己来评估模型。

feature_selection.SelectFromModel

class sklearn.feature_selection.SelectFromModel (estimator, threshold=None, prefit=False, norm_order=1,
max_features=None)

SelectFromModel是一个元变换器,可以与任何在拟合后具有coef_,feature_importances_属性或参数中可选惩罚项的评估器一起使用(比如随机森林和树模型就具有属性feature_importances_,逻辑回归就带有l1和l2惩罚项,线性支持向量机也支持l2惩罚项)。

对于有feature_importances_的模型来说,若重要性低于提供的阈值参数,则认为这些特征不重要并被移除。feature_importances_的取值范围是[0,1],如果设置阈值很小,比如0.001,就可以删除那些对标签预测完全没贡献的特征。如果设置得很接近1,可能只有一两个特征能够被留下。

机器学习实战基础(十七):sklearn中的数据预处理和特征工程(十)特征选择 之 Embedded嵌入法

我们重点要考虑的是前两个参数。在这里,我们使用随机森林为例,则需要学习曲线来帮助我们寻找最佳特征值。

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier as RFC RFC_ = RFC(n_estimators =10,random_state=0) X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y) #在这里我只想取出来有限的特征。0.005这个阈值对于有780个特征的数据来说,是非常高的阈值,因为平均每个特征
只能够分到大约0.001的feature_importances_ X_embedded.shape #模型的维度明显被降低了
#同样的,我们也可以画学习曲线来找最佳阈值 #======【TIME WARNING:10 mins】======# import numpy as np
import matplotlib.pyplot as plt RFC_.fit(X,y).feature_importances_ 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()

机器学习实战基础(十七):sklearn中的数据预处理和特征工程(十)特征选择 之 Embedded嵌入法

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

X_embedded = SelectFromModel(RFC_,threshold=0.00067).fit_transform(X,y)
X_embedded.shape cross_val_score(RFC_,X_embedded,y,cv=5).mean()

可以看出,特征个数瞬间缩小到324多,这比我们在方差过滤的时候选择中位数过滤出来的结果392列要小,并且交叉验证分数0.9399高于方差过滤后的结果0.9388,这是由于嵌入法比方差过滤更具体到模型的表现的缘故,换一个算法,使用同样的阈值,效果可能就没有这么好了。

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

#======【TIME WARNING:10 mins】======#
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()

机器学习实战基础(十七):sklearn中的数据预处理和特征工程(十)特征选择 之 Embedded嵌入法

查看结果,果然0.00067并不是最高点,真正的最高点0.000564已经将模型效果提升到了94%以上。我们使用
0.000564来跑一跑我们的SelectFromModel:

X_embedded = SelectFromModel(RFC_,threshold=0.000564).fit_transform(X,y)
X_embedded.shape cross_val_score(RFC_,X_embedded,y,cv=5).mean() #=====【TIME WARNING:2 min】=====#
#我们可能已经找到了现有模型下的最佳结果,如果我们调整一下随机森林的参数呢?
cross_val_score(RFC(n_estimators=100,random_state=0),X_embedded,y,cv=5).mean()

得出的特征数目依然小于方差筛选,并且模型的表现也比没有筛选之前更高,已经完全可以和计算一次半小时的KNN相匹敌(KNN的准确率是96.58%),接下来再对随机森林进行调参,准确率应该还可以再升高不少。
可见,在嵌入法下,我们很容易就能够实现特征选择的目标:减少计算量,提升模型表现。

因此,比起思考很多统计量的过滤法来说,嵌入法可能是更有效的一种方法。

然而,在算法本身很复杂的时候,过滤法的计算远远比嵌入法要快,所以大型数据中,我们还是会优先考虑过滤法。