python打卡day19

打印 上一主题 下一主题

主题 1745|帖子 1745|积分 5235

特征降维------特征筛选    常见的特征筛选算法
  

  • 方差筛选
  • 皮尔逊相关系数筛选
  • lasso筛选
  • 树模子紧张性
  • shap紧张性
  • 递归特征消除REF
  作业:对心脏病数据集完成特征筛选,对比精度
  
  面对高维特征的时候常常需要引入特征降维,对于某些特征较多的数据,如基因数据、微生物数据、传感器数据等,特征较多,所以会考虑特征降维。特征降维一般有2种计谋:
  1. 特征筛选:从n个特征中筛选出m个特征,好比方差筛选,剔除方差过小的特征;使用皮尔逊相关系数筛选;lasso筛选(lasso自带的系数可以理解为紧张性)、使用树模子自带的紧张性、shap紧张性等筛选;特征递归方法
  2. 特征组合:从n个特征中组合出m个特征,如pca等
  今天这节先说一下特征筛选,!!注意一个点:数据集和训练集分别后分别举行特征筛选,是为了克制数据泄漏。测试集的作用是模拟未知数据,如果在整个数据集上先筛选特征,就相称于用了测试集信息"作弊"了,测试集的信息就会"泄漏"到训练过程中,导致模子评估结果过于乐观。其次,使用训练集确定的筛选标准应用到测试集是保持处理流程的划一性,所有决策依据都来自训练集这个封闭体系,不会导致数据泄漏,区分一下这两个的不同
  1.方差筛选

  核心逻辑是:特征的方差反映了数据的变革程度,方差很小的特征险些没有变革,对模子的预测帮助不大。因此,方差筛选会设定一个方差阈值,剔除方差低于这个阈值的特征,保留那些变革较大的特征,从而淘汰特征数目,提高模子效率(值得注意的是,方差筛选只需要特征数据即可筛选,是无监视筛选,不像其他筛选算法)
  这种方法特别适合处理高维数据,能快速去掉不紧张的特征,但它不考虑特征与目标变量之间的关系,可能会误删一些低方差但故意义的特征
  1. # 打印标题,表明这是方差筛选的部分
  2. print("--- 方差筛选 (Variance Threshold) ---")
  3. # 导入需要的工具库
  4. from sklearn.feature_selection import VarianceThreshold  # 方差筛选工具,用于剔除方差小的特征
  5. import time  # 用于记录代码运行时间,方便比较效率
  6. # 记录开始时间,后面会计算整个过程耗时
  7. start_time = time.time()
  8. # 创建方差筛选器,设置方差阈值为0.01
  9. # 阈值是指方差的最小值,低于这个值的特征会被删除(可以根据数据情况调整阈值)
  10. selector = VarianceThreshold(threshold=0.01)
  11. # 对训练数据进行方差筛选,fit_transform会计算每个特征的方差并剔除不满足阈值的特征
  12. # X_train是原始训练数据,X_train_var是筛选后的训练数据
  13. X_train_var = selector.fit_transform(X_train)
  14. # 对测试数据应用同样的筛选规则,transform会直接用训练数据的筛选结果处理测试数据
  15. # X_test是原始测试数据,X_test_var是筛选后的测试数据
  16. X_test_var = selector.transform(X_test)
  17. # 获取被保留下来的特征名称
  18. # selector.get_support()返回一个布尔值数组,表示哪些特征被保留,如 [True, False, True,...]
  19. # X_train.columns是特征的名称,布尔值数组在这里起一个索引的作用,可以提取保留特征的名字
  20. selected_features_var = X_train.columns[selector.get_support()].tolist()
  21. # 打印筛选后保留的特征数量和具体特征名称,方便查看结果
  22. print(f"方差筛选后保留的特征数量: {len(selected_features_var)}")
  23. print(f"保留的特征: {selected_features_var}")
  24. # 创建一个随机森林分类模型,用于在筛选后的数据上进行训练和预测
  25. # random_state=42是为了保证每次运行结果一致,方便教学和对比
  26. rf_model_var = RandomForestClassifier(random_state=42)
  27. # 在筛选后的训练数据上训练模型
  28. # X_train_var是筛选后的特征数据,y_train是对应的目标标签
  29. rf_model_var.fit(X_train_var, y_train)
  30. # 使用训练好的模型对筛选后的测试数据进行预测
  31. # X_test_var是筛选后的测试特征数据,rf_pred_var是预测结果
  32. rf_pred_var = rf_model_var.predict(X_test_var)
  33. # 记录结束时间,计算整个训练和预测过程的耗时
  34. end_time = time.time()
  35. print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
  36. # 打印模型在测试集上的分类报告,展示模型的性能
  37. # 分类报告包括精确率、召回率、F1分数等指标,帮助评估模型好坏
  38. print("\n方差筛选后随机森林在测试集上的分类报告:")
  39. print(classification_report(y_test, rf_pred_var))
  40. # 打印混淆矩阵,展示模型预测的详细结果
  41. # 混淆矩阵显示了真实标签和预测标签的对应情况,比如多少样本被正确分类,多少被错分
  42. print("方差筛选后随机森林在测试集上的混淆矩阵:")
  43. print(confusion_matrix(y_test, rf_pred_var))
复制代码

  2.皮尔逊相关系数筛选

  核心逻辑是:计算每个特征与目标变量之间的相关系数,然后根据相关系数的绝对值巨细,选择与目标变量相关性较高的特征,剔除相关性较低的特征。这种方法实用于目标变量是一连型的环境(如果是分类题目,可以先对目标变量编码转换成数值型,用的时候设定参数score_func=f_classif就行,封装好了不需要手动编码
  1. print("--- 皮尔逊相关系数筛选 ---")
  2. from sklearn.feature_selection import SelectKBest, f_classif
  3. import time
  4. start_time = time.time()
  5. # 计算特征与目标变量的相关性,选择前k个特征(这里设为10个,可调整)
  6. # 注意:皮尔逊相关系数通常用于回归问题(连续型目标变量),但如果目标是分类问题,可以用f_classif
  7. k = 10
  8. selector = SelectKBest(score_func=f_classif, k=k)
  9. X_train_corr = selector.fit_transform(X_train, y_train)
  10. X_test_corr = selector.transform(X_test)
  11. # 获取筛选后的特征名
  12. selected_features_corr = X_train.columns[selector.get_support()].tolist()
  13. print(f"皮尔逊相关系数筛选后保留的特征数量: {len(selected_features_corr)}")
  14. print(f"保留的特征: {selected_features_corr}")
  15. # 训练随机森林模型
  16. rf_model_corr = RandomForestClassifier(random_state=42)
  17. rf_model_corr.fit(X_train_corr, y_train)
  18. rf_pred_corr = rf_model_corr.predict(X_test_corr)
  19. end_time = time.time()
  20. print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
  21. print("\n皮尔逊相关系数筛选后随机森林在测试集上的分类报告:")
  22. print(classification_report(y_test, rf_pred_corr))
  23. print("皮尔逊相关系数筛选后随机森林在测试集上的混淆矩阵:")
  24. print(confusion_matrix(y_test, rf_pred_corr))
复制代码

  3.lasso筛选(基于L1正则化)

  核心逻辑是:在举行线性回归的同时,通过引入L1正则化项(即处罚项),强制将一些不紧张特征的回归系数压缩到0,从而实现特征筛选。换句话说,Lasso会自动“挑选”对预测目标有贡献的特征(系数不为0),而剔除无关或冗余的特征(系数为0)
  1. print("--- Lasso筛选 (L1正则化) ---")
  2. from sklearn.linear_model import Lasso
  3. from sklearn.feature_selection import SelectFromModel
  4. import time
  5. start_time = time.time()
  6. # 使用Lasso回归进行特征筛选
  7. lasso = Lasso(alpha=0.01, random_state=42)  # alpha值可调整
  8. selector = SelectFromModel(lasso)
  9. selector.fit(X_train, y_train)
  10. X_train_lasso = selector.transform(X_train)
  11. X_test_lasso = selector.transform(X_test)
  12. # 获取筛选后的特征名
  13. selected_features_lasso = X_train.columns[selector.get_support()].tolist()
  14. print(f"Lasso筛选后保留的特征数量: {len(selected_features_lasso)}")
  15. print(f"保留的特征: {selected_features_lasso}")
  16. # 训练随机森林模型
  17. rf_model_lasso = RandomForestClassifier(random_state=42)
  18. rf_model_lasso.fit(X_train_lasso, y_train)
  19. rf_pred_lasso = rf_model_lasso.predict(X_test_lasso)
  20. end_time = time.time()
  21. print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
  22. print("\nLasso筛选后随机森林在测试集上的分类报告:")
  23. print(classification_report(y_test, rf_pred_lasso))
  24. print("Lasso筛选后随机森林在测试集上的混淆矩阵:")
  25. print(confusion_matrix(y_test, rf_pred_lasso))
复制代码

  Lasso本质是线性回归模子,要求目标变量是一连值,但分类题目的目标变量是离散类别,强行用回归方法处理分类题目会带来理论缺陷,把类别标签0/1看成一连数值处理,拟合的是"用特征预测0到1之间的数值"的回归题目,固然确实能计算
  4.树模子紧张性

  依赖于树模子自带的内部评估的特征选择,在训练时让模子自己告诉哪些特征最紧张
  1. print("--- 树模型自带的重要性筛选 ---")
  2. from sklearn.feature_selection import SelectFromModel
  3. import time
  4. start_time = time.time()
  5. # 使用随机森林的特征重要性进行筛选
  6. rf_selector = RandomForestClassifier(random_state=42)
  7. rf_selector.fit(X_train, y_train)
  8. selector = SelectFromModel(rf_selector, threshold="mean")  # 阈值设为平均重要性,可调整
  9. X_train_rf = selector.transform(X_train)
  10. X_test_rf = selector.transform(X_test)
  11. # 获取筛选后的特征名
  12. selected_features_rf = X_train.columns[selector.get_support()].tolist()
  13. print(f"树模型重要性筛选后保留的特征数量: {len(selected_features_rf)}")
  14. print(f"保留的特征: {selected_features_rf}")
  15. # 训练随机森林模型
  16. rf_model_rf = RandomForestClassifier(random_state=42)
  17. rf_model_rf.fit(X_train_rf, y_train)
  18. rf_pred_rf = rf_model_rf.predict(X_test_rf)
  19. end_time = time.time()
  20. print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
  21. print("\n树模型重要性筛选后随机森林在测试集上的分类报告:")
  22. print(classification_report(y_test, rf_pred_rf))
  23. print("树模型重要性筛选后随机森林在测试集上的混淆矩阵:")
  24. print(confusion_matrix(y_test, rf_pred_rf))
复制代码

  疑问点:为什么创建了两次随机森林分类器?
  答:第一次创建 rf_selector 是专门用于特征紧张性评估,传入的是原始的 x_train,第二次创建 rf_model_rf 是用筛选后的特征训练终极预测模子,传入的是筛选后的 x_train_rf,让特征选择和终极模子实现了隔离,克制数据泄漏
  5.shap紧张性

  通过shap值本来就可以可视化特征的紧张程度,这是之前讲过的,不外多赘述了
  (从之前的学习来说,shap紧张性还是不太适合维度过大的数据,shap值运算很耗时的,比起其他筛选算法不太划算,发起在高维场景下先用快速方法降维,再局部使用SHAP举行精细筛选)
  1. print("--- SHAP重要性筛选 ---")
  2. import shap
  3. from sklearn.feature_selection import SelectKBest
  4. import time
  5. start_time = time.time()
  6. # 使用随机森林模型计算SHAP值
  7. rf_shap = RandomForestClassifier(random_state=42)
  8. rf_shap.fit(X_train, y_train)
  9. explainer = shap.TreeExplainer(rf_shap)
  10. shap_values = explainer.shap_values(X_train)
  11. # 计算每个特征的平均SHAP值(取绝对值的平均,可以只在乎贡献大小而不关心方向)
  12. mean_shap = np.abs(shap_values[1]).mean(axis=0)  # shap_values[1]对应正类
  13. k = 10  # 选择前10个特征,可调整
  14. top_k_indices = np.argsort(mean_shap)[-k:] # 返回数值从小到大排序的重要特征列索引位置,取最后K个
  15. X_train_shap = X_train.iloc[:, top_k_indices]
  16. X_test_shap = X_test.iloc[:, top_k_indices]
  17. # 获取筛选后的特征名
  18. selected_features_shap = X_train.columns[top_k_indices].tolist()
  19. print(f"SHAP重要性筛选后保留的特征数量: {len(selected_features_shap)}")
  20. print(f"保留的特征: {selected_features_shap}")
  21. # 训练随机森林模型
  22. rf_model_shap = RandomForestClassifier(random_state=42)
  23. rf_model_shap.fit(X_train_shap, y_train)
  24. rf_pred_shap = rf_model_shap.predict(X_test_shap)
  25. end_time = time.time()
  26. print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
  27. print("\nSHAP重要性筛选后随机森林在测试集上的分类报告:")
  28. print(classification_report(y_test, rf_pred_shap))
  29. print("SHAP重要性筛选后随机森林在测试集上的混淆矩阵:")
  30. print(confusion_matrix(y_test, rf_pred_shap))
复制代码

  6.递归特征消除REF

  核心头脑是通过递归地移除最不紧张的特征,逐步缩小特征集,直到达到预设的特征数目或满足其他克制条件
  1. print("--- 递归特征消除 (RFE) ---")
  2. from sklearn.feature_selection import RFE
  3. import time
  4. start_time = time.time()
  5. # 使用随机森林作为基础模型进行RFE
  6. base_model = RandomForestClassifier(random_state=42)
  7. rfe = RFE(base_model, n_features_to_select=10)  # 选择10个特征,可调整
  8. rfe.fit(X_train, y_train)
  9. X_train_rfe = rfe.transform(X_train)
  10. X_test_rfe = rfe.transform(X_test)
  11. # 获取筛选后的特征名
  12. selected_features_rfe = X_train.columns[rfe.support_].tolist()
  13. print(f"RFE筛选后保留的特征数量: {len(selected_features_rfe)}")
  14. print(f"保留的特征: {selected_features_rfe}")
  15. # 训练随机森林模型
  16. rf_model_rfe = RandomForestClassifier(random_state=42)
  17. rf_model_rfe.fit(X_train_rfe, y_train)
  18. rf_pred_rfe = rf_model_rfe.predict(X_test_rfe)
  19. end_time = time.time()
  20. print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
  21. print("\nRFE筛选后随机森林在测试集上的分类报告:")
  22. print(classification_report(y_test, rf_pred_rfe))
  23. print("RFE筛选后随机森林在测试集上的混淆矩阵:")
  24. print(confusion_matrix(y_test, rf_pred_rfe))
复制代码

  @浙大疏锦行

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户云卷云舒

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表