特征选择实战:Sklearn 3大方法(Filter/Wrapper/Embedded)对比与20维数据集应用

📅 2026/7/9 3:44:39
特征选择实战:Sklearn 3大方法(Filter/Wrapper/Embedded)对比与20维数据集应用
特征选择实战三大方法对比与20维数据集深度应用引言在机器学习项目中我们常常面临维度灾难的挑战。当数据集包含大量特征时不仅会增加计算成本还可能导致模型过拟合。特征选择技术通过识别最具预测力的特征子集成为解决这一问题的关键工具。本文将聚焦Scikit-learn中Filter、Wrapper和Embedded三大类特征选择方法通过一个20维的模拟数据集带您深入掌握特征选择的工程实践。与理论讲解不同本文强调实战应用。我们将从数据生成开始逐步演示每种方法的实现细节并通过量化指标对比它们的性能差异。无论您是希望优化现有模型的数据科学家还是需要处理高维数据的工程师这些实战技巧都能直接应用于您的工作场景。1. 实验环境与数据准备1.1 工具链配置首先确保已安装必要的Python库import numpy as np import pandas as pd from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.feature_selection import (VarianceThreshold, SelectKBest, chi2, RFE, SelectFromModel) from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, f1_score import matplotlib.pyplot as plt1.2 生成模拟数据集我们创建一个包含20个特征其中5个为信息特征的二分类数据集# 生成具有信息特征和噪声特征的分类数据集 X, y make_classification( n_samples1000, n_features20, n_informative5, n_redundant2, n_repeated0, n_classes2, random_state42 ) # 转换为DataFrame便于分析 feature_names [fFeature_{i} for i in range(X.shape[1])] df pd.DataFrame(X, columnsfeature_names) df[Target] y # 数据标准化 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.3, random_state42 )1.3 数据探索查看特征的基本统计信息print(f数据集形状: {df.shape}) print(\n前5行数据:) print(df.head()) print(\n特征描述统计:) print(df.describe()) print(\n类别分布:) print(df[Target].value_counts())可视化特征分布plt.figure(figsize(12, 6)) df[feature_names[:5]].boxplot() plt.title(前5个特征的分布) plt.xticks(rotation45) plt.show()2. Filter方法实战Filter方法基于特征的统计特性进行选择独立于任何机器学习算法。它们计算效率高适合作为预处理步骤。2.1 方差阈值法移除低方差特征假设方差小于0.8selector VarianceThreshold(threshold0.8) X_train_variance selector.fit_transform(X_train) # 查看被保留的特征 selected_features np.array(feature_names)[selector.get_support()] print(f保留的特征数量: {len(selected_features)}) print(f被保留的特征: {selected_features})2.2 卡方检验选择与目标变量最相关的k个特征这里k10chi2_selector SelectKBest(chi2, k10) X_train_chi2 chi2_selector.fit_transform(X_train, y_train) # 获取特征得分 chi2_scores pd.DataFrame({ Feature: feature_names, Chi2_Score: chi2_selector.scores_ }).sort_values(Chi2_Score, ascendingFalse) print(\n卡方检验特征排名:) print(chi2_scores) # 可视化得分 plt.figure(figsize(10, 6)) plt.barh(chi2_scores[Feature], chi2_scores[Chi2_Score]) plt.title(卡方检验特征重要性) plt.xlabel(卡方得分) plt.show()2.3 互信息法衡量特征与目标变量的非线性关系from sklearn.feature_selection import mutual_info_classif mi_scores mutual_info_classif(X_train, y_train, random_state42) mi_df pd.DataFrame({ Feature: feature_names, MI_Score: mi_scores }).sort_values(MI_Score, ascendingFalse) print(\n互信息特征排名:) print(mi_df) # 选择Top 10特征 top_mi_features mi_df.head(10)[Feature].values X_train_mi X_train[:, [feature_names.index(f) for f in top_mi_features]]3. Wrapper方法实战Wrapper方法通过训练模型来评估特征子集的质量虽然计算成本较高但通常能获得更好的性能。3.1 递归特征消除(RFE)使用逻辑回归作为基模型逐步剔除最不重要的特征lr LogisticRegression(max_iter1000, random_state42) rfe RFE(estimatorlr, n_features_to_select10, step1) X_train_rfe rfe.fit_transform(X_train, y_train) # 查看特征排名 rfe_ranking pd.DataFrame({ Feature: feature_names, RFE_Ranking: rfe.ranking_ }).sort_values(RFE_Ranking) print(\nRFE特征排名:) print(rfe_ranking) # 可视化特征选择过程 plt.figure(figsize(10, 6)) plt.plot(range(1, len(rfe.grid_scores_) 1), rfe.grid_scores_) plt.xlabel(特征数量) plt.ylabel(交叉验证得分) plt.title(RFE特征选择过程) plt.show()3.2 顺序特征选择实现前向和后向选择策略from sklearn.feature_selection import SequentialFeatureSelector # 前向选择 sfs_forward SequentialFeatureSelector( lr, n_features_to_select10, directionforward ) X_train_sfs_forward sfs_forward.fit_transform(X_train, y_train) # 后向选择 sfs_backward SequentialFeatureSelector( lr, n_features_to_select10, directionbackward ) X_train_sfs_backward sfs_backward.fit_transform(X_train, y_train) print(\n前向选择保留的特征:) print(np.array(feature_names)[sfs_forward.get_support()]) print(\n后向选择保留的特征:) print(np.array(feature_names)[sfs_backward.get_support()])4. Embedded方法实战Embedded方法在模型训练过程中自动进行特征选择结合了Filter和Wrapper的优点。4.1 Lasso回归使用L1正则化进行特征选择from sklearn.linear_model import LogisticRegressionCV lasso LogisticRegressionCV( penaltyl1, solverliblinear, cv5, random_state42 ) lasso.fit(X_train, y_train) # 查看系数 coef_df pd.DataFrame({ Feature: feature_names, Coefficient: lasso.coef_[0] }).sort_values(Coefficient, keyabs, ascendingFalse) print(\nLasso回归系数:) print(coef_df) # 选择非零系数特征 selected_lasso_features coef_df[coef_df[Coefficient] ! 0][Feature].values X_train_lasso X_train[:, [feature_names.index(f) for f in selected_lasso_features]]4.2 随机森林特征重要性利用树模型的内置特征重要性评估rf RandomForestClassifier(n_estimators100, random_state42) rf.fit(X_train, y_train) # 获取特征重要性 importance_df pd.DataFrame({ Feature: feature_names, Importance: rf.feature_importances_ }).sort_values(Importance, ascendingFalse) print(\n随机森林特征重要性:) print(importance_df) # 可视化 plt.figure(figsize(10, 6)) plt.barh(importance_df[Feature], importance_df[Importance]) plt.title(随机森林特征重要性) plt.xlabel(重要性得分) plt.show()4.3 梯度提升树特征选择使用XGBoost进行特征选择from xgboost import XGBClassifier xgb XGBClassifier(random_state42) xgb.fit(X_train, y_train) # 获取特征重要性 xgb_importance pd.DataFrame({ Feature: feature_names, XGB_Importance: xgb.feature_importances_ }).sort_values(XGB_Importance, ascendingFalse) print(\nXGBoost特征重要性:) print(xgb_importance) # 选择重要性大于平均值的特征 threshold xgb_importance[XGB_Importance].mean() selected_xgb_features xgb_importance[xgb_importance[XGB_Importance] threshold][Feature].values X_train_xgb X_train[:, [feature_names.index(f) for f in selected_xgb_features]]5. 方法对比与结果分析5.1 评估指标定义我们使用以下指标评估不同特征选择方法选择的特征数量测试集准确率F1分数训练时间def evaluate_features(X_train_selected, X_test_selected, model): start_time time.time() model.fit(X_train_selected, y_train) train_time time.time() - start_time y_pred model.predict(X_test_selected) acc accuracy_score(y_test, y_pred) f1 f1_score(y_test, y_pred) return { Num_Features: X_train_selected.shape[1], Accuracy: acc, F1_Score: f1, Train_Time: train_time }5.2 结果对比准备测试集的特征子集# 获取各方法选择的特征索引 methods { VarianceThreshold: selected_features, Chi2: chi2_scores.head(10)[Feature].values, MutualInfo: top_mi_features, RFE: np.array(feature_names)[rfe.support_], Lasso: selected_lasso_features, RandomForest: importance_df.head(10)[Feature].values, XGBoost: selected_xgb_features } # 初始化结果表 results [] # 评估各方法 lr_model LogisticRegression(max_iter1000, random_state42) for method_name, features in methods.items(): # 获取特征索引 feature_indices [feature_names.index(f) for f in features] X_train_selected X_train[:, feature_indices] X_test_selected X_test[:, feature_indices] # 评估 metrics evaluate_features(X_train_selected, X_test_selected, lr_model) metrics[Method] method_name results.append(metrics) # 转换为DataFrame results_df pd.DataFrame(results).set_index(Method) print(\n各方法性能对比:) print(results_df.sort_values(F1_Score, ascendingFalse))5.3 可视化对比绘制各方法性能对比图fig, axes plt.subplots(2, 2, figsize(14, 10)) # 特征数量对比 results_df[Num_Features].plot.bar(axaxes[0,0], colorskyblue) axes[0,0].set_title(选择的特征数量) axes[0,0].set_ylabel(数量) # 准确率对比 results_df[Accuracy].plot.bar(axaxes[0,1], colorsalmon) axes[0,1].set_title(测试集准确率) axes[0,1].set_ylim(0.8, 1.0) # F1分数对比 results_df[F1_Score].plot.bar(axaxes[1,0], colorlightgreen) axes[1,0].set_title(测试集F1分数) axes[1,0].set_ylim(0.8, 1.0) # 训练时间对比 results_df[Train_Time].plot.bar(axaxes[1,1], colorgold) axes[1,1].set_title(训练时间(秒)) plt.tight_layout() plt.show()6. 工程实践建议6.1 方法选择指南根据我们的实验结果和实际经验总结以下选择建议场景推荐方法理由初步特征筛选方差阈值卡方检验计算高效快速去除无关特征高维数据(n1000)互信息随机森林能捕捉非线性关系适合大数据线性关系强的数据Lasso回归自动特征选择解释性强计算资源充足RFEXGBoost性能最优但耗时较长需要模型解释性Lasso/随机森林提供特征重要性排序6.2 特征选择流程推荐的特征选择工作流数据预处理处理缺失值、异常值标准化/归一化初步筛选使用方差阈值去除低方差特征单变量分析应用卡方检验或互信息进行初步特征排名模型选择线性模型尝试L1正则化方法树模型利用内置特征重要性精细筛选对候选特征子集使用RFE或顺序选择验证评估在独立测试集上验证最终特征集的效果6.3 常见问题解决方案问题1选择的特征过多提高方差阈值增加正则化强度降低Wrapper方法中的特征数量参数问题2重要特征被遗漏检查特征预处理是否正确尝试不同的特征选择方法组合验证特征间是否存在高度相关性问题3选择结果不稳定增加数据量使用交叉验证尝试集成特征选择方法# 集成特征选择示例结合多种方法的结果 from sklearn.feature_selection import SelectFromModel # 使用随机森林和Lasso的结果 combined_features set(importance_df.head(8)[Feature]).union( set(coef_df.head(8)[Feature]) ) print(f集成选择得到的特征: {combined_features})7. 扩展应用与进阶技巧7.1 自定义特征选择器创建结合业务知识的自定义选择器from sklearn.base import BaseEstimator, TransformerMixin class CustomFeatureSelector(BaseEstimator, TransformerMixin): def __init__(self, business_rulesNone): self.business_rules business_rules or {} def fit(self, X, yNone): # 这里可以添加基于业务规则的特征选择逻辑 if must_include in self.business_rules: self.keep_features_ self.business_rules[must_include] else: # 默认保留所有特征 self.keep_features_ list(range(X.shape[1])) return self def transform(self, X): return X[:, self.keep_features_] # 使用示例 business_rules {must_include: [0, 2, 5]} # 必须包含的特征索引 custom_selector CustomFeatureSelector(business_rules) X_train_custom custom_selector.fit_transform(X_train)7.2 特征选择流水线构建包含特征选择的完整机器学习流水线from sklearn.pipeline import Pipeline from sklearn.model_selection import GridSearchCV # 定义流水线 pipe Pipeline([ (variance_threshold, VarianceThreshold()), (feature_selector, SelectKBest(chi2)), (classifier, LogisticRegression()) ]) # 设置参数网格 param_grid { variance_threshold__threshold: [0, 0.5, 1.0], feature_selector__k: [5, 10, 15], classifier__C: [0.1, 1, 10] } # 网格搜索 grid_search GridSearchCV(pipe, param_grid, cv5, scoringf1) grid_search.fit(X_train, y_train) print(\n最佳参数组合:) print(grid_search.best_params_) print(f最佳F1分数: {grid_search.best_score_:.4f})7.3 特征稳定性分析评估特征选择结果的稳定性from sklearn.utils import resample # 多次采样评估特征选择稳定性 n_iterations 10 feature_counts {f: 0 for f in feature_names} for _ in range(n_iterations): # 自助采样 X_resampled, y_resampled resample(X_train, y_train, random_state_) # 应用特征选择 selector SelectKBest(chi2, k10) selector.fit(X_resampled, y_resampled) # 统计被选中的特征 for i, selected in enumerate(selector.get_support()): if selected: feature_counts[feature_names[i]] 1 # 打印特征选择频率 stability_df pd.DataFrame.from_dict(feature_counts, orientindex, columns[Count]) stability_df stability_df.sort_values(Count, ascendingFalse) print(\n特征选择稳定性分析:) print(stability_df)