[机器学习与scikit-learn-51]:特征工程-特征选择

[机器学习与scikit-learn-51]:特征工程-特征选择,第1张

作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/124232476


目录

前言:

第1章 嵌入法简介

1.1 简介

1.2 模型

1.3 缺点

第2章 scikit-learn提供的接口:feature_selection.SelectFromModel

2.1 原型

2.2 使用条件

第3章 代码示例

3.1 手工指过滤定门限

3.2 交叉验证的分数

3.3 通过学习曲线确定最优thres_hold的范围

3.4 进一步细化学习曲线,寻找最优门限

3.5 进一步确认

3.6 通过调整随机深林算法的超参数来提升分数


前言:

过滤样本的特征,有两种基本的阶段,一是在算法之前先过滤特征,然后进行算法训练,另一种阶段就是,有些算法提供了一边进行算法训练,一边进行特征选择的方法,这种方法称为嵌入式特征过滤法。其基本思想是在训练过程中检测哪些特征对训练的影响较大(梯度较大),然后忽略梯度较小的特征。

第1章 嵌入法简介 1.1 简介

嵌入法是一种让算法自己决定选择或使用哪些特征的方法,即特征选择和算法训练同时进行。

在使用嵌入法时,我们先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据权值系数从大到小选择特征。

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

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

1.2 模型

1.3 缺点

(1)权限系数的门限指标确定困难

过滤法中使用的统计量,可以使用统计知识和常识来查找或确定特征的范围(如p值应当低于显著性水平0.05)。

而嵌入法中使用的权值系数却没有这样的范围可找——我们可以说,权值系数为0的特征对模型丝毫没有作用,但当大量特征都对模型有贡献且贡献不一时,我们就很难去界定一个有效的临界值。

这种情况下,模型权值系数就是我们的超参数,需要通过学习曲线,或者根据模型本身的某些性质去判断这个超参数的最佳值究竟应该是多少。

(2)耗时,效率低

嵌入法引入了算法来挑选特征,因此其计算速度也会和应用的算法有很大的关系。

如果采用计算量很大,计算缓慢的算法,嵌入法本身也会非常耗时耗力。

并且,在选择完毕之后,我们还是需要自己来评估模型。

第2章 scikit-learn提供的接口:feature_selection.SelectFromModel 2.1 原型

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

 (1)estimator:算法模型

(2)特征的权重门限

(3)max_features:选择的特征个数限制

2.2 使用条件

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

对于有feature_importances_的模型来说,若重要性低于提供的阈值参数,则认为这些特征不重要并被移除。

feature_importances_的取值范围是[0,1],如果设置阈值很小,比如0.001,就可以删除那些对标签预测完全没贡献的特征。如果设置得很接近1,可能只有一两个特征能够被留下。

SelectFromModel是根据在算法运算过程中,生成的feature_importances_值来进行特征选择的,如果一个算法无法提供feature_importances_,则不能使用SelectFromModel来选择特征,无法通过该方法对特征进行降维。

第3章 代码示例 3.1 手工指过滤定门限
# 特征过滤:嵌入法:在算法运行中选择最优特征
from sklearn.feature_selection import SelectFromModel

# 分类算法:随机森林
from sklearn.ensemble import RandomForestClassifier as RFC

# 构建随机森林模型对象
RFC_ = RFC(n_estimators =10,random_state=0)

print("原始样本的形状X.shape:", X.shape)

# 模型训练
RFC_After = RFC_.fit(X,y)

# 获取特征
feature_importances = RFC_After.feature_importances_
print("不同特征权重的形状", feature_importances.shape)
print("特征权重最大值:", feature_importances.max())
data = np.flipud(np.sort(feature_importances))
print("前五个特征的权重", data[0:5])

# threshold:指定需要过滤掉的特征的权重系数的门限
thres_hold = 0.005

# 嵌入式
# RFC_: 指定算法模型
# 0.005这个阈值对于有780个特征的数据来说,是非常高的阈值,
# 因为平均每个特征只能够分到大约0.001的feature_importances_
# X: 没有经过方差过滤的原始数据集
# y:样本标签
RFC_embeded = SelectFromModel(RFC_, threshold=thres_hold)
# 使用没有过滤的原始特征数据X
X_embedded = RFC_embeded.fit_transform(X,y)

# 过滤后,还剩下47个特征
print("嵌入式过滤后的样本:", X_embedded.shape)

# 模型的维度明显被降低了
# 那么thres_hold为多少时是最优的呢????
原始样本的形状X.shape: (42000, 784)
不同特征权重的形状 (784,)
特征权重最大值: 0.01276360214820271
前五个特征的权重 [0.0127636  0.01127749 0.01046941 0.01033262 0.01028841]
嵌入式过滤后的样本: (42000, 47)

备注:

在手工指定门限thres_hold = 0.005的情况下,过滤后的特征值个数只有47个。

thres_hold = 0.005门限是最优的吗? 47个特征值是合适的吗?

3.2 交叉验证的分数
# 过滤后特征
X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y)
print("过滤后的特征", X_embedded.shape)

# 过滤后的模型,交叉验证模型的分数
score=cross_val_score(RFC_,X_embedded,y,cv=5).mean()
print("过滤后的交叉验证分数",score)
过滤后的特征 (42000, 47)
过滤后的交叉验证分数 0.8947619047619048

备注:0.89的分数有点低,什么样的门限是合适的呢?

3.3 通过学习曲线确定最优thres_hold的范围
#同样的,我们也可以画学习曲线来找最佳阈值 !!!
#======【TIME WARNING:10 mins】======#
import numpy as np
import matplotlib.pyplot as plt
 
RFC_.fit(X,y).feature_importances_

# 构建学习曲线的门限数据集
# 门限的范围=【0,特征权重的最大值】
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()

# 权重的门限越低(过低掉无关紧要的特征),分数越高,耗时越长
# 门限越高(过低掉越重要的特征),分数越低,耗时越短
# 我们需要在效率和分数之间取得一个平衡。

 从上图可以看出,当门限落在【0, 0.002】之间时,交叉验证的分数是比较高的。

如何进一步确定这个门限呢?

3.4 进一步细化学习曲线,寻找最优门限
#======【TIME WARNING:10 mins】======#
# 构建新的学习曲线
# 门限的范围=【0,特征权重的最大值】
threshold_up = 0.001
threshold_num = 60
thresholds_list = np.linspace(0,threshold_up, threshold_num)
threshold_best = 0
score_list = []
score_best = 0

# 寻找最佳门限(交叉验证分数最高时对应的门限)
for i in thresholds_list:
    X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
    once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
    score_list.append(once)
    if(once > thresholds_best):
        thresholds_best = i
        score_best = once
# 绘制图像
plt.figure(figsize=[threshold_num,5])
plt.plot(thresholds_list ,score_list)
plt.xticks(np.linspace(0,threshold_up, threshold_num))
plt.show()

print("过滤后的特征", X_embedded.shape)
print("Best threshold:", thresholds_best)
print("Best core:", score_best)
过滤后的特征 (42000, 279)
Best threshold: 0.001
Best core: 0.9386904761904763
3.5 进一步确认
X_embedded = SelectFromModel(RFC_,threshold=0.000564).fit_transform(X,y)
X_embedded.shape
 
cross_val_score(RFC_,X_embedded,y,cv=5).mean()
0.9392857142857144
3.6 通过调整随机深林算法的超参数来提升分数
#=====【TIME WARNING:2 min】=====#
#我们可能已经找到了现有模型下的最佳结果,如果我们调整一下随机森林的参数呢?
cross_val_score(RFC(n_estimators=100,random_state=0),X_embedded,y,cv=5).mean()
0.9634285714285715

作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/124232476

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/715606.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存