4. 特征工程(下):特征选择与降维

各位同行,咱们接着聊特征工程。上一节我们把特征构建和编码讲完了,这一节要啃的硬骨头是——特征选择特征降维

说实话,这两个概念很多人容易搞混。我刚开始做风电数据分析时,也傻傻分不清。简单说:特征选择是“做减法”,从一堆特征里挑出有用的;特征降维是“做变形”,把高维数据压缩到低维空间。两者目标一样——干掉冗余,提升模型性能。

特征工程(下)知识体系 特征选择 • 过滤式:方差阈值、卡方检验、互信息 • 包裹式:递归特征消除(RFE) • 嵌入式:Lasso、树模型特征重要性 特征降维 • PCA:主成分分析(线性降维) • t-SNE:t分布随机邻域嵌入(非线性) • 应用场景:可视化、去噪、加速训练 vs 共同目标 减少过拟合 · 提升计算效率 · 增强模型可解释性 实战流程:原始数据 → 特征构建 → 特征选择 → 特征降维 → 建模评估

一、特征选择:三种主流方法

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