尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

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

特征选择实战:Sklearn 3大方法(Filter/Wrapper/Embedded)对比与20维数据集应用
📅 发布时间:2026/7/9 4:00:24

特征选择实战:三大方法对比与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 plt

1.2 生成模拟数据集

我们创建一个包含20个特征(其中5个为信息特征)的二分类数据集:

# 生成具有信息特征和噪声特征的分类数据集 X, y = make_classification( n_samples=1000, n_features=20, n_informative=5, n_redundant=2, n_repeated=0, n_classes=2, random_state=42 ) # 转换为DataFrame便于分析 feature_names = [f'Feature_{i}' for i in range(X.shape[1])] df = pd.DataFrame(X, columns=feature_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_size=0.3, random_state=42 )

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(rotation=45) plt.show()

2. Filter方法实战

Filter方法基于特征的统计特性进行选择,独立于任何机器学习算法。它们计算效率高,适合作为预处理步骤。

2.1 方差阈值法

移除低方差特征(假设方差小于0.8):

selector = VarianceThreshold(threshold=0.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个特征(这里k=10):

chi2_selector = SelectKBest(chi2, k=10) 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', ascending=False) 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_state=42) mi_df = pd.DataFrame({ 'Feature': feature_names, 'MI_Score': mi_scores }).sort_values('MI_Score', ascending=False) 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_iter=1000, random_state=42) rfe = RFE(estimator=lr, n_features_to_select=10, step=1) 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_select=10, direction='forward' ) X_train_sfs_forward = sfs_forward.fit_transform(X_train, y_train) # 后向选择 sfs_backward = SequentialFeatureSelector( lr, n_features_to_select=10, direction='backward' ) 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( penalty='l1', solver='liblinear', cv=5, random_state=42 ) lasso.fit(X_train, y_train) # 查看系数 coef_df = pd.DataFrame({ 'Feature': feature_names, 'Coefficient': lasso.coef_[0] }).sort_values('Coefficient', key=abs, ascending=False) 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_estimators=100, random_state=42) rf.fit(X_train, y_train) # 获取特征重要性 importance_df = pd.DataFrame({ 'Feature': feature_names, 'Importance': rf.feature_importances_ }).sort_values('Importance', ascending=False) 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_state=42) xgb.fit(X_train, y_train) # 获取特征重要性 xgb_importance = pd.DataFrame({ 'Feature': feature_names, 'XGB_Importance': xgb.feature_importances_ }).sort_values('XGB_Importance', ascending=False) 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_iter=1000, random_state=42) 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', ascending=False))

5.3 可视化对比

绘制各方法性能对比图:

fig, axes = plt.subplots(2, 2, figsize=(14, 10)) # 特征数量对比 results_df['Num_Features'].plot.bar(ax=axes[0,0], color='skyblue') axes[0,0].set_title('选择的特征数量') axes[0,0].set_ylabel('数量') # 准确率对比 results_df['Accuracy'].plot.bar(ax=axes[0,1], color='salmon') axes[0,1].set_title('测试集准确率') axes[0,1].set_ylim(0.8, 1.0) # F1分数对比 results_df['F1_Score'].plot.bar(ax=axes[1,0], color='lightgreen') axes[1,0].set_title('测试集F1分数') axes[1,0].set_ylim(0.8, 1.0) # 训练时间对比 results_df['Train_Time'].plot.bar(ax=axes[1,1], color='gold') axes[1,1].set_title('训练时间(秒)') plt.tight_layout() plt.show()

6. 工程实践建议

6.1 方法选择指南

根据我们的实验结果和实际经验,总结以下选择建议:

场景推荐方法理由
初步特征筛选方差阈值+卡方检验计算高效,快速去除无关特征
高维数据(n>1000)互信息+随机森林能捕捉非线性关系,适合大数据
线性关系强的数据Lasso回归自动特征选择,解释性强
计算资源充足RFE+XGBoost性能最优,但耗时较长
需要模型解释性Lasso/随机森林提供特征重要性排序

6.2 特征选择流程

推荐的特征选择工作流:

  1. 数据预处理:处理缺失值、异常值,标准化/归一化
  2. 初步筛选:使用方差阈值去除低方差特征
  3. 单变量分析:应用卡方检验或互信息进行初步特征排名
  4. 模型选择:
    • 线性模型:尝试L1正则化方法
    • 树模型:利用内置特征重要性
  5. 精细筛选:对候选特征子集使用RFE或顺序选择
  6. 验证评估:在独立测试集上验证最终特征集的效果

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_rules=None): self.business_rules = business_rules or {} def fit(self, X, y=None): # 这里可以添加基于业务规则的特征选择逻辑 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, cv=5, scoring='f1') 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, k=10) 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, orient='index', columns=['Count']) stability_df = stability_df.sort_values('Count', ascending=False) print("\n特征选择稳定性分析:") print(stability_df)

相关新闻

  • 使用CC Switch管理Codex需切换API地址的原因
  • OpenClaw专栏第六篇:Docker Compose一键部署与集群扩展
  • AD5593R与MSP432P401R的硬件协同设计与信号处理

最新新闻

  • 性价比高的GEO优化解决措施服务商企业
  • 显存不足?出图模糊?崩溃频发?Stable Diffusion十大高频故障,99%用户都在踩的坑,现在立刻修复
  • SCADA系统选型五大要点,机加工企业别再花冤枉钱了
  • 2026企业400电话服务商深度测评|运营商直营、低价代理、一级授权服务商全方位对比
  • 如今投资网站域名还是一门好生意吗?AI 时代下的域名价值正在变化
  • 扩展 Lucas 定理(exLucas)学习笔记 详解,一文带你彻底看懂扩展 Lucas 定理。---------------------著作权归作者所有。商业转载请联系作者获得授权,非商业

日新闻

  • SQL 查询语句的标准逻辑执行顺序(即语义处理顺序),它与实际书写顺序不同,但决定了数据库如何解析和执行查询
  • ORB-SLAM2 重定位模块深度解析:从 BoW 候选帧到 PnP 优化的 6 步流程
  • 罗技鼠标宏压枪脚本终极指南:从原理到实战的完整解析

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号