4. 特征工程(下):特征选择与降维
各位同行,咱们接着聊特征工程。上一节我们把特征构建和编码讲完了,这一节要啃的硬骨头是——特征选择和特征降维。
说实话,这两个概念很多人容易搞混。我刚开始做风电数据分析时,也傻傻分不清。简单说:特征选择是“做减法”,从一堆特征里挑出有用的;特征降维是“做变形”,把高维数据压缩到低维空间。两者目标一样——干掉冗余,提升模型性能。
一、特征选择:三种主流方法
1. 过滤式(Filter)—— 先筛后练
过滤式方法,说白了就是不依赖任何模型,直接拿统计指标给特征打分。速度快,适合大规模数据。
常用的指标有:
- 方差阈值:方差太小的特征,基本没啥变化,留着干嘛?
- 卡方检验:适合分类问题,看特征和目标变量是否独立。
- 互信息:能捕捉非线性关系,比相关系数更灵活。
实战经验:我在处理风机的振动数据时,有200多个频域特征。用互信息一筛,发现只有30多个跟轴承故障强相关。剩下的全是噪声,果断扔掉。
from sklearn.feature_selection import SelectKBest, mutual_info_classif
# 假设 X 是特征矩阵,y 是故障标签
selector = SelectKBest(score_func=mutual_info_classif, k=30)
X_selected = selector.fit_transform(X, y)
print("选中的特征索引:", selector.get_support(indices=True))
小技巧:过滤式方法适合做“粗筛”,先干掉明显没用的特征,再交给后面的方法细挑。
2. 包裹式(Wrapper)—— 模型说了算
包裹式方法,是把特征选择包在模型训练里面。每次选一组特征,训练模型看效果,再调整特征组合。
最经典的是递归特征消除(RFE):
- 先拿所有特征训练模型
- 根据特征重要性,干掉最不重要的那个
- 重复以上步骤,直到特征数达标
注意:包裹式方法计算量很大。我曾经在80维特征上用RFE,跑了整整两个小时。如果你的数据量很大,建议先用过滤式降维。
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
# 用随机森林做包裹式选择
estimator = RandomForestClassifier(n_estimators=100)
selector = RFE(estimator, n_features_to_select=15, step=1)
selector.fit(X_train, y_train)
print("特征排名:", selector.ranking_)
3. 嵌入式(Embedded)—— 边训练边选
嵌入式方法,把特征选择嵌入到模型训练过程中。模型自己会决定哪些特征重要。
两个典型代表:
- Lasso回归:L1正则化会让不重要的特征系数变成0
- 树模型特征重要性:随机森林、XGBoost都能输出特征重要性排序
我的习惯:做风电项目时,我一般先用随机森林跑一遍特征重要性,把排名后50%的特征直接扔掉。然后再用Lasso做二次筛选。这样又快又稳。
from sklearn.linear_model import Lasso
# Lasso自动做特征选择
lasso = Lasso(alpha=0.01)
lasso.fit(X_scaled, y)
selected_features = X.columns[lasso.coef_ != 0]
print(f"Lasso选中了 {len(selected_features)} 个特征")
二、特征降维:PCA 与 t-SNE
特征选择是“挑”,特征降维是“变”。降维后的每个维度,都是原始特征的某种组合。
1. PCA(主成分分析)—— 线性降维的扛把子
PCA的原理,就是把原始特征投影到方差最大的方向上。说白了,就是找数据“变化最剧烈”的那些方向。
我举个例子:风机有风速、转速、温度、振动等20个特征。PCA之后,可能前3个主成分就解释了90%的方差。那后面的17个维度,基本就是噪声。
避坑指南:PCA对数据尺度敏感。一定要先做标准化,否则量纲大的特征会主导主成分。我曾经吃过这个亏,后来养成了先标准化再PCA的习惯。
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
# 标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# PCA降维到10维
pca = PCA(n_components=10)
X_pca = pca.fit_transform(X_scaled)
print("解释方差比:", pca.explained_variance_ratio_)
print("累计解释方差:", sum(pca.explained_variance_ratio_))
| 主成分 | 解释方差比 | 累计解释方差 | 主要关联特征 |
|---|---|---|---|
| PC1 | 0.45 | 0.45 | 风速、功率、转速 |
| PC2 | 0.28 | 0.73 | 温度、振动幅值 |
| PC3 | 0.12 | 0.85 | 桨距角、偏航误差 |
2. t-SNE —— 可视化神器
t-SNE(t分布随机邻域嵌入)是非线性降维方法。它特别擅长把高维数据映射到2D或3D,让你一眼看出数据的聚类结构。
为什么叫t-SNE?因为它用t分布来计算低维空间的相似度,能更好地拉开不同类别的距离。
实战场景:我在做风机故障诊断时,用t-SNE把20维的振动特征降到2维。画出来一看,正常样本和齿轮箱故障样本分得清清楚楚。拿去给领导汇报,一张图就讲明白了。
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
# t-SNE降维到2维
tsne = TSNE(n_components=2, random_state=42, perplexity=30)
X_tsne = tsne.fit_transform(X_scaled)
# 可视化
plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='viridis', alpha=0.7)
plt.colorbar(scatter, label='故障类型')
plt.title('t-SNE 降维可视化 - 风机故障数据')
plt.xlabel('t-SNE 维度1')
plt.ylabel('t-SNE 维度2')
plt.show()
注意:t-SNE的计算复杂度是O(n²),数据量超过1万条就会很慢。而且每次运行结果可能不一样,因为它是随机初始化的。我一般先用PCA降到50维,再用t-SNE降到2维,这样又快又稳。
三、如何选择?一张表说清楚
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 过滤式 | 高维数据、快速筛选 | 速度快、不依赖模型 | 忽略特征交互 |
| 包裹式 | 特征数少、追求精度 | 考虑特征组合效果 | 计算量大、易过拟合 |
| 嵌入式 | 常规建模、兼顾效率 | 边训练边选、效果好 | 依赖模型选择 |
| PCA | 线性降维、去噪 | 解释性强、计算快 | 丢失非线性信息 |
| t-SNE | 可视化、探索分析 | 聚类效果明显 | 计算慢、不可逆 |
我的建议:实际项目中,别纠结选哪个。我的流程是:先用过滤式粗筛 → 再用嵌入式精挑 → 最后用PCA降维加速。如果要做可视化,再加个t-SNE。这套组合拳,我用了好几年,没出过问题。
好了,特征工程这部分就讲完了。下一节我们进入模型训练环节,到时候会用到今天讲的特征选择和降维技巧。记住一句话:好的特征,胜过复杂的模型。
公众号:蓝海资料掘金营,微信deep3321