特征选择三剑客:过滤法、包装法与嵌入法的实战对比

张开发
2026/4/12 3:55:21 15 分钟阅读

分享文章

特征选择三剑客:过滤法、包装法与嵌入法的实战对比
1. 特征选择为什么重要在机器学习项目中我们经常会遇到成百上千个特征但并不是所有特征都对预测有帮助。有些特征可能是冗余的有些可能是噪声甚至有些特征会干扰模型的判断。这就好比你要做一道菜面前摆着几十种调料但真正需要的可能只有盐、糖、酱油等几种关键调料。放太多无关调料反而会让菜品味道变得奇怪。特征选择就是在做这个挑选关键调料的工作。它能带来三个明显好处提升模型性能去除无关特征后模型能更专注于真正有用的信息加快训练速度特征越少计算量越小训练速度自然越快增强可解释性使用少量关键特征建立的模型更容易理解和解释我在实际项目中就遇到过这样的情况一个包含200多个特征的数据集经过特征选择后只用30个特征模型准确率反而提高了5%训练时间缩短了60%。2. 过滤法简单高效的初筛工具2.1 方差选择法 - 剔除僵尸特征想象一下如果某个特征在所有样本中的值都差不多比如所有人的身高都是1.75米这个特征显然对分类没有帮助。方差选择法就是通过计算特征的方差来识别这类僵尸特征。from sklearn.feature_selection import VarianceThreshold from sklearn.datasets import load_iris # 加载鸢尾花数据集 iris load_iris() # 设置方差阈值为0.8 selector VarianceThreshold(threshold0.8) X_new selector.fit_transform(iris.data) print(原始特征数:, iris.data.shape[1]) print(筛选后特征数:, X_new.shape[1])这个方法特别适合作为特征选择的第一道筛子能快速剔除明显无用的特征。但要注意阈值的选择——设得太高可能误删有用特征太低则起不到筛选效果。我一般会先观察特征的方差分布再决定合适的阈值。2.2 相关系数法 - 找出与目标最相关的特征相关系数法就像给每个特征和目标之间做相亲匹配看它们是否合适。我们常用皮尔逊相关系数来衡量线性相关性值在-1到1之间绝对值越大相关性越强。from sklearn.feature_selection import SelectKBest from scipy.stats import pearsonr import numpy as np # 自定义评分函数 def pearson_selector(X, y): scores [] for i in range(X.shape[1]): score pearsonr(X[:, i], y)[0] scores.append((abs(score), i)) # 按得分排序 scores.sort(reverseTrue) return np.array(scores) # 选择top 2特征 selector SelectKBest(pearson_selector, k2) X_new selector.fit_transform(iris.data, iris.target)这个方法计算简单、解释性强但有个明显局限只能检测线性关系。如果特征和目标是非线性关系可能会漏掉重要特征。我在处理金融数据时就遇到过这种情况后来改用互信息法才解决了问题。3. 包装法让模型自己选特征3.1 递归特征消除(RFE) - 逐步剔除最差特征RFE的工作方式很像我们整理衣柜先把最不常穿的衣服挑出来扔掉然后看看剩下的衣服再挑最不常穿的扔掉如此反复直到剩下最精华的部分。from sklearn.feature_selection import RFE from sklearn.linear_model import LogisticRegression from sklearn.datasets import make_classification # 生成模拟数据 X, y make_classification(n_samples1000, n_features20, n_informative5) # 使用逻辑回归作为基模型 estimator LogisticRegression() selector RFE(estimator, n_features_to_select5, step1) X_new selector.fit_transform(X, y) print(特征排名:, selector.ranking_) print(被选中的特征:, selector.support_)RFE的优点是考虑特征组合效应选出的特征子集通常质量较高。但缺点也很明显计算成本高特别是特征多的时候。我建议先用过滤法做初步筛选再用RFE精挑细选。3.2 顺序特征选择(SFS) - 逐步添加最佳特征与RFE相反SFS是从空集开始逐步添加最能提升模型性能的特征。就像玩拼图每次都找最能提升完整度的那块。from sklearn.feature_selection import SequentialFeatureSelector from sklearn.neighbors import KNeighborsClassifier knn KNeighborsClassifier(n_neighbors3) sfs SequentialFeatureSelector(knn, n_features_to_select5) X_new sfs.fit_transform(X, y) print(被选中的特征:, sfs.support_)包装法最大的优势是考虑特征间的相互作用选出的特征组合通常能带来更好的模型性能。但代价是需要反复训练模型计算量很大。对于特征特别多的情况建议先做过滤法降维。4. 嵌入法训练和选择一步到位4.1 L1正则化(Lasso) - 自动特征选择Lasso回归就像个严格的教练训练时会把不重要的特征的系数压缩为零相当于自动做了特征选择。from sklearn.linear_model import Lasso from sklearn.preprocessing import StandardScaler # 数据标准化很重要 scaler StandardScaler() X_scaled scaler.fit_transform(X) lasso Lasso(alpha0.1) lasso.fit(X_scaled, y) # 查看系数不为零的特征被选中 print(特征系数:, lasso.coef_)Lasso特别适合特征间存在多重共线性的情况。但要注意alpha参数的选择——太大可能把有用特征也压缩为零太小则选择不够严格。我通常会用交叉验证来寻找最佳alpha值。4.2 树模型特征重要性 - 基于信息增益的选择决策树类模型在训练时会自动评估特征重要性就像老师能看出哪些学生最用功一样。from sklearn.ensemble import RandomForestClassifier rf RandomForestClassifier(n_estimators100) rf.fit(X, y) # 获取特征重要性 importances rf.feature_importances_ indices np.argsort(importances)[::-1] # 打印特征排名 for f in range(X.shape[1]): print(f{f1}. 特征 {indices[f]} - 重要性: {importances[indices[f]]:.4f})树模型的特征选择对非线性关系很有效而且能处理各种类型的数据。但要注意如果特征间相关性很强重要性可能会被分散。我在实践中发现配合一些降维方法使用效果更好。5. 方法对比与实战建议5.1 三种方法性能对比方法类型计算成本考虑特征交互适用场景典型算法过滤法低否初步筛选、大数据集方差选择、相关系数包装法高是中小数据集、追求性能RFE、SFS嵌入法中部分模型训练时选择Lasso、树模型5.2 如何选择合适的方法根据我的项目经验可以遵循以下原则数据量很大(10万样本)先用过滤法快速降维再考虑其他方法特征间相关性高优先考虑L1正则化或树模型追求最佳模型性能尝试包装法特别是RFE需要解释特征重要性树模型或Lasso是不错的选择一个典型的处理流程可能是用方差选择法去除零方差特征用相关系数或互信息法去除低相关特征用Lasso或树模型进一步筛选最后用RFE精选特征子集5.3 实际案例房价预测特征选择最近做一个房价预测项目时我尝试了不同方法先用方差阈值0.1去除了15个低方差特征再用互信息法选出top 30特征最后用XGBoost的特征重要性确定了10个关键特征这个组合使模型RMSE降低了12%训练时间缩短了40%。特别是发现距地铁站距离这个特征比所在区域更重要这与业务直觉一致增强了模型可信度。

更多文章