24·数据处理进阶

特征选择:过滤法、包装法与嵌入法

feature-engineeringmodel-selection

第 24 课 - 特征选择:过滤法、包装法与嵌入法

学习目标

完成本课学习后,你将能够:

  1. 理解为什么特征选择对机器学习模型至关重要,并能说出其核心益处。
  2. 区分过滤法、包装法和嵌入法这三种主要特征选择策略的核心思想与区别。
  3. 使用 Python 中的 scikit-learn 库,分别实践三种方法进行特征选择。
  4. 了解不同方法的适用场景、优缺点,并能在实践中选择合适的方法。

核心概念

在上一课“特征工程”中,我们学会了创造新特征。但有时,我们面对的是一个“特征过多”的问题。想象一下,你要用1000个特征来预测一个结果,其中可能900个都是噪音或冗余信息。这不仅会增加计算成本,还可能让模型“学坏”(过拟合),降低泛化能力。

特征选择 就是一个“去粗取精”的过程,目标是从原始特征集中,选出一个对预测目标最有用的子集。

我们可以用一个“选拔运动员”的比喻来理解三种主流方法:

  • 过滤法:像“体检筛选”。我们用一些独立于机器学习模型的统计指标(如特征与目标的相关性、特征本身的方差)来给每个特征打分,直接过滤掉得分低的。它简单快速,但完全忽略了特征之间的相互作用。
  • 包装法:像“试训选拔”。我们把某个特定的机器学习模型(如逻辑回归、随机森林)当作“教练”,让它亲自尝试不同的特征子集,并评估哪个子集能让模型在验证集上表现最好。它直接优化模型性能,但计算开销非常大。
  • 嵌入法:像“教练内行推荐”。我们在训练某个特定模型的过程中,让模型自身通过其学习机制来“标识”出哪些特征最重要。例如,带有L1正则化的模型(Lasso)在训练时会自动将不重要的特征的系数压至零。它是过滤法和包装法的一个折中。

代码示例

我们将使用 scikit-learn 内置的乳腺癌数据集,这是一个二分类数据集,共有30个特征。

# 导入必要的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import SelectKBest, f_classif, RFE
from sklearn.ensemble import RandomForestClassifier

# 1. 加载数据
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target
print(f"原始特征数量: {X.shape[1]}")

# 2. 数据预处理:标准化(对某些方法很重要)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 3. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.3, random_state=42)

# --- 过滤法示例:使用方差和ANOVA F值 ---
print("\n--- 过滤法 (Filter Methods) ---")
# 方法1: 移除低方差特征 (方差为0的特征显然无用)
from sklearn.feature_selection import VarianceThreshold
selector_var = VarianceThreshold(threshold=0.5) # 设置方差阈值
X_train_var = selector_var.fit_transform(X_train)
print(f"移除低方差特征后,剩余特征数量: {X_train_var.shape[1]}")

# 方法2: 基于单变量统计检验 (ANOVA F值) 选择前10个特征
selector_kbest = SelectKBest(score_func=f_classif, k=10)
X_train_kbest = selector_kbest.fit_transform(X_train, y_train)
# 查看被选中的特征
selected_features_kbest = X.columns[selector_kbest.get_support()]
print(f"基于ANOVA F值选择的前10个特征: {list(selected_features_kbest)}")

# --- 包装法示例:递归特征消除 (RFE) ---
print("\n--- 包装法 (Wrapper Methods) ---")
# 使用一个基础模型(如逻辑回归)作为评估器
estimator = LogisticRegression(max_iter=1000, random_state=42)
# 创建RFE对象,要求选择10个特征
selector_rfe = RFE(estimator, n_features_to_select=10, step=1)
selector_rfe.fit(X_train, y_train)
selected_features_rfe = X.columns[selector_rfe.support_]
print(f"RFE选择的特征: {list(selected_features_rfe)}")

# --- 嵌入法示例:基于L1正则化的选择 ---
print("\n--- 嵌入法 (Embedded Methods) ---")
# L1正则化 (Lasso) 会将不重要的特征的系数压为0
lasso = LogisticRegression(penalty='l1', solver='liblinear', C=0.1, random_state=42)
lasso.fit(X_train, y_train)
# 查看系数为0的特征(即被“淘汰”的)
coefficients = lasso.coef_[0]
zero_coeff_features = X.columns[coefficients == 0]
print(f"L1正则化置为0的特征 ({len(zero_coeff_features)}个): {list(zero_coeff_features)}")

# 另一种常见的嵌入法:基于树模型的特征重要性
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
# 特征重要性排序
importances = rf.feature_importances_
sorted_idx = np.argsort(importances)[::-1]
print("\n基于随机森林的特征重要性排序(前10):")
for idx in sorted_idx[:10]:
    print(f"{X.columns[idx]}: {importances[idx]:.4f}")

实践练习

  1. 过滤法练习:请修改上面的过滤法代码,使用 SelectKBestchi2(卡方检验)方法从数据集 X 中选择前 5 个特征。打印出被选中的特征名称。 提示:注意卡方检验要求特征值非负,因此你需要先对数据进行 Min-Max 缩放,或者使用 SelectKBest 配合 mutual_info_classif 函数。

  2. 包装法练习:将包装法示例中的基础模型从 LogisticRegression 换成 RandomForestClassifier,再次使用 RFE 选择 8 个特征。比较与使用逻辑回归时选出的特征有何不同。 要求:打印出新选出的 8 个特征,并与上一个示例的 10 个特征做对比,简述你的观察。

  3. 嵌入法与模型评估:使用嵌入法(L1正则化)得到的非零系数特征,训练一个新的逻辑回归模型,并评估其在测试集上的准确率。同时,使用全部特征也训练一个模型并评估,对比两者的性能差异。 预期输出:一个打印语句,显示使用全部特征和使用选择后特征的模型在测试集上的准确率。

常见错误

  1. 过度依赖单一方法:不要只使用一种方法就认为完成任务。尝试结合多种方法,或对比不同方法的结果,以获得更可靠的特征子集。
  2. 忽略特征间的相关性:过滤法中的单变量统计(如ANOVA、卡方)独立评估每个特征,可能会选择多个高度相关的冗余特征。在实际应用中,可以先做相关性分析,手动移除一些冗余特征。
  3. 在数据分割前进行特征选择这是一个严重的数据泄露错误! 特征选择的过程(如计算相关性、训练RFE)必须仅在训练集上进行,然后将同样的选择规则应用到测试集。在上面的代码中,我们正是这样做的 (fit_transformX_train 上)。
  4. 忘记标准化:对于基于距离或梯度的包装法(如RFE配合逻辑回归)和嵌入法(Lasso),特征缩放非常重要。未经缩放的数据可能导致选择偏向数值范围大的特征。

小结

  • 特征选择旨在移除无关、冗余或噪声特征,以提升模型性能、减少过拟合和加速训练。
  • 过滤法:快速、独立于模型。依赖统计测试(方差、相关系数、卡方、F值、互信息)。适合作为初步筛选。
  • 包装法:将特征选择视为搜索问题,使用模型性能作为评价标准。效果好但计算成本高。典型代表是递归特征消除(RFE)。
  • 嵌入法:在模型训练过程中自动完成特征选择。兼顾了过滤法的效率和包装法的准确性。L1正则化和基于树的特征重要性是常见技术。
  • 实践黄金法则:始终在独立的训练集上进行特征选择操作,避免数据泄露。

练习编辑器

rust
Loading...

继续学习

完成本课后,建议继续学习下一课「数据标准化与归一化」 以巩固所学知识。