1. 特征选择分类
| 类型 | 方法 | 特点 |
| 过滤法 | 统计检验 | 快,不考虑模型 |
| 包裹法 | 模型评估 | 慢,考虑模型 |
| 嵌入法 | 模型内置 | 折中 |
2. 过滤法
方差阈值(删低方差)、ANOVA F值、卡方检验、互信息(检测非线性)
VIF>10→严重共线性→删除VIF最高的迭代
3. 包裹法
RFE(递归特征消除)、RFECV(自动确定特征数)、前向选择、后向消除
问题:计算量大(2^p)、过拟合风险、不稳定
4. 嵌入法
Lasso(L1)→稀疏选择、树模型特征重要性、ElasticNet
排列重要性: 打乱特征值看性能下降(模型无关)。SHAP值: 每个特征的边际贡献。
Python代码实现与验证
💡 代码说明:以下代码使用 Python / Scikit-learn 实现,已实机运行验证。
完整代码
import numpy as np
from sklearn.datasets import make_classification, load_iris
from sklearn.feature_selection import SelectKBest, f_classif, mutual_info_classif, RFE, VarianceThreshold
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import pandas as pd
np.random.seed(42)
X,y = make_classification(n_samples=500, n_features=20, n_informative=5, random_state=42)
X[:,0]=1.0; X[:,1]*=0.001
print("=== 方差阈值 ===")
vt = VarianceThreshold(0.01)
print("原始20特征 -> 过滤后{}特征".format(vt.fit_transform(X).shape[1]))
print("\n=== 单变量选择 ===")
for k in [3,5,10]:
pipe = Pipeline([('skb',SelectKBest(f_classif,k=k)),('s',StandardScaler()),('lr',LogisticRegression(max_iter=200))])
s = cross_val_score(pipe, X, y, cv=5)
print("K={}: 准确率={:.4f}".format(k, s.mean()))
print("\n=== 互信息 ===")
mi = mutual_info_classif(X,y,random_state=42)
print("Top5特征: {} 值: {}".format(np.argsort(mi)[-5:], mi[np.argsort(mi)[-5:]].round(4)))
print("\n=== RFE ===")
rfe = RFE(LogisticRegression(max_iter=1000), n_features_to_select=5)
rfe.fit(StandardScaler().fit_transform(X),y)
print("选择特征: {}".format(np.where(rfe.support_)[0]))
l1 = LogisticRegression(penalty='l1',solver='saga',C=0.1,max_iter=2000)
l1.fit(StandardScaler().fit_transform(X),y)
print("\nL1非零系数: {}/20".format(np.sum(np.abs(l1.coef_)>0.001)))
运行结果
=== 方差阈值 ===
原始20特征 -> 过滤后18特征
=== 单变量选择 ===
K=3: 准确率=0.7720
K=5: 准确率=0.8480
K=10: 准确率=0.8520
=== 互信息 ===
Top5特征: [ 9 2 8 16 4] 值: [0.1087 0.113 0.1142 0.1321 0.2032]
=== RFE ===
选择特征: [ 2 4 10 11 16]
L1非零系数: 7/20
✅ 验证通过
深入理解:特征工程的精髓
"特征工程是决定模型上限的关键"
业界共识:好的特征工程比好的模型更重要。一个线性模型配上优秀特征可以超越复杂模型配普通特征。
特征工程流程
- 理解业务:领域知识是最好的特征来源
- EDA发现:从数据中发现模式→构造特征
- 变换:对数/Box-Cox处理偏态,分箱处理非线性
- 编码:类别→数值,选择合适编码方式
- 缩放:数值特征标准化/归一化
- 选择:删除无关/冗余特征
- 验证:交叉验证评估特征贡献
Kaggle竞赛中的特征工程技巧
- 目标编码:高基数类别特征的杀手锏(需防泄露)
- 交叉特征:两个特征的组合可能产生强信号
- 聚合特征:按组统计(均值/标准差/排名)
- 时间特征:周期编码(sin/cos)保持连续性
- 计数特征:出现频率/缺失次数
- 差分特征:当前值与历史均值的偏差
常见特征工程错误
- 数据泄露:在特征构造中使用了未来信息
- 目标泄露:特征中包含了目标变量的信息
- 过拟合特征:在训练集上有效但测试集失效
- 忽略缺失模式:缺失本身可能是有价值的特征
- 不验证:没有用交叉验证确认特征的实际贡献
进阶特征工程技巧
Kaggle竞赛中的特征工程
在Kaggle竞赛中,特征工程是区分Top 1%和Top 10%的关键。以下是从顶级选手那里学到的技巧:
聚合特征:对时序数据,按实体ID聚合历史行为的统计量——均值、标准差、最小最大、趋势斜率、最近N次的均值变化。这些"在用户层面的历史摘要"往往是最强特征。
目标编码:高基数类别特征(如城市名2000+类)的杀手锏。关键:必须在5折CV内计算,使用平滑参数防止小样本类别不稳定。公式:enc = (count*mean + m*global_mean)/(count+m),m通常取10-100。
比率特征:两个相关特征的比值常常比原始特征更有信息量。贷款金额/年收入、月供/月收入、信用额度使用率等。这些比率捕捉了"相对"而非"绝对"信息。
数据泄露防范完整清单
- 目标泄露:特征包含目标信息——检查每个特征与目标的互信息
- 时间泄露:用了未来数据——特征构造时只用截止时间前的数据
- 组泄露:同组数据分布在训练和测试集——使用GroupKFold
- 预处理泄露:全数据fit scaler——用Pipeline自动处理
- 特征选择泄露:在CV外选特征——特征选择必须在CV内
缺失值处理策略决策树
- 缺失率>50% → 考虑删除特征,但添加缺失指示列
- MCAR(完全随机缺失) → 均值/中位数填充即可
- MAR(与已观测变量相关) → MICE/KNN填充
- MNAR(与缺失值本身相关) → 添加指示列+敏感性分析
- 模型内置 → XGBoost/LightGBM可原生处理缺失值
交叉验证的常见错误
错误的交叉验证比没有交叉验证更危险——它给你虚假的信心。
- 在CV外做特征选择 → 所有折都"看到"了测试数据
- 时间序列数据用K-Fold → 未来数据泄露到训练集
- 同用户数据跨越训练和验证 → 过于乐观的估计
- 超参数调优后"验证" → 测试集已成为验证集
- 不固定随机种子 → 结果不可复现
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
补充:关键概念与面试要点
核心直觉
- 正则化 = 给模型加"约束",防止过度拟合噪声
- 交叉验证 = "用数据的不同部分反复检验模型"
- 特征选择 = "选择携带最多目标信息的特征"
- 集成学习 = "三个臭皮匠顶个诸葛亮"
- 降维 = "抓住主要矛盾"
常见面试问题
- L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
- 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
- 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
- K-Means为什么收敛到局部最优?(目标函数非凸)
- PCA为什么需要中心化?(否则第一主成分指向均值方向)
📝 课后练习
- 实现本课核心算法并用Scikit-learn验证
- 调优关键超参数并记录性能变化
- 用交叉验证评估模型稳定性
- 与之前学过的方法对比分析
- 分析本课方法的失效条件