Day 19 常见的特征筛选算法(续)

@浙大疏锦行

在昨天的学习中,了解了常见的特征筛选方法中的四种:方差筛选、皮尔逊系数筛选、Lasso筛选以及树模型自带的重要性筛选。

今日将接着学习剩下的SHAP重要性筛选以及RFE筛选,并对心脏数据集实践特征筛选的过程。

SHAP重要性筛选

基于SHAP值的模型解释性的高级特征选择方法。根据每个特征对模型预测的贡献度大小排序,选择最重要的k个特征。

具体而言,步骤如下:

  1. 训练模型并创建shap解释器,计算shap值
  2. 计算SHAP值的平均值,得到特征的全局重要性
  3. 排序并选择top-k特征,使用特征索引筛选训练集和测试集的对应特征iloc
  4. 重新训练,对比结果
import shap

start_time = time.time()
#计算shap值
rf_shap = RandomForestClassifier(random_state=42)
rf_shap.fit(X_train,y_train)
explainer = shap.TreeExplainer(rf_shap)
shap_values = explainer.shap_values(X_train) #耗时长

#筛选特征
#取绝对值是为了排除方向的影响,取平均是为了得到每个特征的全局重要性,axis=0按行
mean_shap = np.abs(shap_values[:,:,1]).mean(axis=0) #shap_values[:,:,1])获取正类的特征与样本
#排序并选择重要特征,np.argsort()返回数组排序后的索引数组
k = 10
top_k_indices = np.argsort(mean_shap)[-k:] #获取前k个重要特征的索引,重要性逐渐降低
X_train_shap = X_train.iloc[:,top_k_indices] #训练集的特征筛选,iloc方法切片
X_test_shap = X_test.iloc[:,top_k_indices] #测试集的特征筛选

#查看特征
selected_features_shap = X_train.columns[top_k_indices].tolist()
print('保留特征:{}, \n数量:{}'.format(selected_features_shap,len(selected_features_shap)))

#重新训练
rf_model_shap = RandomForestClassifier(random_state=42)
rf_model_shap.fit(X_train_shap,y_train)
rf_pred_shap = rf_model_shap.predict(X_test_shap)
end_time = time.time()
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\nSHAP筛选后随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_shap))
print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_shap))

通过SHAP筛选前10个特征,进行训练得到如下结果:

递归特征消除RFE

递归特征消除法(Recursive Feature Elimination,RFE),属于包裹法,通过递归地构建模型并剔除最不重要的特征,最终保留最优的特征子集。它是一个反复迭代的过程,每次迭代都会训练一个模型,根据特征重要性排序,淘汰掉最不重要的特征,直到达到指定的特征数量。

递归特征消除法筛选特征可以通过sklearn中的RFE(estimator,n_features_to_select,...)实现:

from sklearn.feature_selection import RFE

start_time = time.time()
#创建模型并训练
rf_rfe = RandomForestClassifier(random_state=42)
k = 10
selector = RFE(estimator=rf_rfe,n_features_to_select=k)
selector.fit(X_train,y_train)
X_train_rfe = selector.transform(X_train)
X_test_rfe = selector.transform(X_test)
#查看特征
selected_features_rfe = X_train.columns[selector.get_support()].tolist()
print('保留特征:{}, \n数量:{}'.format(selected_features_rfe,len(selected_features_rfe)))
#重新训练模型
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train,y_train)
rf_pred = rf_model.predict(X_test)
end_time = time.time()

print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\nRFE 随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred))
print("RFE 随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred))

通过RFE筛选前10个特征,进行训练得到如下结果:

综上,通过这六种特征筛选方法后,可以发现,将特征数降低之后,模型的效果并没有大幅度下降。

下面是六种方法的对比,实际使用中可以采用组合的方法。此外还可以从下几方面考虑:

  • 数据量:小用RFE,大用Lasso或方差
  • 关系类型:线性用皮尔逊或Lasso,非线性用树模型或SHAP
  • 解释需求:高用SHAP,低用树模型或RFE
  • 计算资源:充足用SHAP或RFE,紧张用方差或皮尔逊
方法原理优点缺点适用场景
方差筛选移除低方差特征速度快、简单忽略与目标关系数据预处理
皮尔逊系数线性相关性计算快、易解释仅线性关系线性问题初步筛选
Lasso筛选L1正则化自动选择、处理高维线性假设高维数据、线性模型
树模型重要性基于树模型捕捉非线性、高效可能偏向高基数树模型、非线性数据
SHAP筛选特征贡献度解释性最强、统一度量计算成本高可解释性要求高
RFE筛选递归消除效果优、找到最优子集计算慢、不稳定中等数据集、追求性能

作业:心脏病数据集特征筛选

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
 
# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei']  # Windows系统常用黑体字体
plt.rcParams['axes.unicode_minus'] = False    # 正常显示负号
#读取数据
data = pd.read_csv(r'heart.csv')
data.head() #读取前5行
 
#对于多分类特征进行独热编码
continous_features = ['age','trestbps','chol','thalach','oldpeak']
discrete_features = ['sex','cp','fbs','restecg','exang','slope','thal']
multi_features = ['cp','restecg','slope','thal']
data = pd.get_dummies(data=data,columns=multi_features,prefix=multi_features) #返回的是新的dataframe+编码列
data.head()
 
#标签和特征
X = data.drop(['target'],axis=1)
y = data['target']
 
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,train_size=0.7,random_state=42)

#没有进行特征筛选
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score
from sklearn.metrics import classification_report,confusion_matrix
import warnings
warnings.filterwarnings('ignore') # 忽略所有警告信息
import time

start_time = time.time()
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train,y_train)
rf_pred = rf_model.predict(X_test)
end_time = time.time()

print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\n默认随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred))
print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred))

 

默认随机森林:

由于筛选方法与信贷数据集没有什么区别,流程和代码基本相同,下面只展示结果:

(1)方差筛选,选取了22个特征,结果与默认差别不大

(2)皮尔逊系数,选取了10个特征,结果与默认有差距

(3)Lasso筛选,选取了15个特征,结果与默认有差距

(4)树模型自带,选取了10个特征,结果与默认有差距

(5)shap筛选,选取了10个特征,结果与默认有差距

(6)RFE,选取了10个特征,结果与默认相同

对比特征筛选前后的结果,发现方差筛选和RFE筛选,两种方法的结果与默认的几乎无差别。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值