3、特征工程评估:特征相关性分析、特征重要性排序、特征冗余检测
特征工程做完了,模型也跑了几轮,这时候你是不是觉得可以松口气了?
别急。我见过太多人把一堆特征扔进模型,结果精度上不去,还找不出原因。说白了,特征不是越多越好。你想想看,一堆冗余特征堆在一起,模型反而会被带偏。
这一节,我们就来聊聊怎么给特征做「体检」。三个维度:相关性分析、重要性排序、冗余检测。一个一个来。
3.1 特征相关性分析
为什么要做相关性分析?
举个例子。我在一个风场项目中,发现振动特征和温度特征的相关性高达0.92。当时我就觉得不对劲。果然,这两个特征其实描述的是同一个物理现象——轴承磨损。你留一个就够了,两个反而让模型过拟合。
常用的方法有两种:
- 皮尔逊相关系数:适合线性关系,取值范围[-1, 1]
- 斯皮尔曼秩相关系数:适合非线性关系,对异常值不敏感
我个人习惯先用皮尔逊扫一遍,看到绝对值大于0.8的,再手动确认一下。代码很简单:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# 假设 df 是特征数据框
corr_matrix = df.corr(method='pearson')
# 热力图可视化
plt.figure(figsize=(12, 10))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f')
plt.title('特征相关性热力图')
plt.show()
重点:相关性高 ≠ 特征冗余。比如温度和转速,物理上确实相关,但两者对寿命预测的贡献不同。这时候不要急着删,先看重要性排序。
3.2 特征重要性排序
特征重要性排序,说白了就是给每个特征打个分,看看谁对模型贡献大。
我常用的方法有三种:
- 基于树模型的特征重要性:比如随机森林、XGBoost,自带 feature_importances_ 属性
- 置换重要性(Permutation Importance):打乱某个特征的值,看模型精度下降多少
- SHAP 值:基于博弈论,能解释每个特征对每个样本的贡献
嗯,这里要注意。树模型的重要性容易偏向数值型特征,而且对高基数类别特征不友好。我建议你至少用两种方法交叉验证。
举个例子,我曾经用随机森林跑出一个结果,排名第一的特征是「风速标准差」。但用 SHAP 一看,其实「齿轮箱油温」对尾部样本的预测影响更大。这就是为什么不能只看一种方法。
from sklearn.ensemble import RandomForestRegressor
import shap
# 训练模型
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# 方法1:树模型自带重要性
importances = model.feature_importances_
feature_names = X_train.columns
# 方法2:SHAP 值
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)
# 可视化
shap.summary_plot(shap_values, X_test, feature_names=feature_names)
小技巧:如果特征数量超过50个,先跑一次随机森林,只保留前20个重要特征,再去做 SHAP 分析。不然计算量太大,我吃过这个亏。
3.3 特征冗余检测
冗余检测和相关性分析不一样。相关性高不一定冗余,但冗余的特征一定相关性高。
怎么判断冗余?我一般看两个指标:
- 方差膨胀因子(VIF):VIF > 10 说明存在严重多重共线性
- 互信息(Mutual Information):衡量两个特征之间的信息重叠量
VIF 的计算很简单:
from statsmodels.stats.outliers_influence import variance_inflation_factor
def calculate_vif(df):
vif_data = pd.DataFrame()
vif_data['feature'] = df.columns
vif_data['VIF'] = [variance_inflation_factor(df.values, i) for i in range(df.shape[1])]
return vif_data
vif_result = calculate_vif(X_train)
print(vif_result[vif_result['VIF'] > 10])
避坑指南:我曾经在一个项目中,VIF 算出来有20多个特征都大于10。当时我一股脑全删了,结果模型精度掉了5个点。后来才发现,有些特征虽然共线性高,但它们的交互作用对预测很重要。所以,VIF 只作为参考,不要一刀切。
互信息的方法更适合非线性场景。比如两个特征,一个是指数增长,一个是线性增长,皮尔逊相关系数可能很低,但互信息能捕捉到它们的信息重叠。
from sklearn.feature_selection import mutual_info_regression
mi = mutual_info_regression(X_train, y_train)
mi_series = pd.Series(mi, index=X_train.columns).sort_values(ascending=False)
print(mi_series.head(10))
3.4 综合评估流程
好了,三个维度都讲完了。那在实际项目中,怎么串起来?
我个人习惯按这个顺序走:
- 先做相关性分析,找出高相关特征对(|r| > 0.8)
- 再做重要性排序,看这些高相关特征中,哪些对模型贡献大
- 最后做冗余检测,对贡献小且冗余的特征,果断删除
你想想看,这个流程其实就是一个「先粗筛、再精筛」的过程。不会漏掉重要特征,也不会保留无用特征。
核心原则:保留「重要且不冗余」的特征,删除「不重要且冗余」的特征。对于「重要但冗余」的特征,可以考虑做特征融合,比如 PCA 降维。
下面这张图是我自己总结的评估流程,你可以参考一下:
最后说一句,特征评估不是一次性工作。模型迭代过程中,特征的重要性可能会变。我建议你每个季度重新跑一次这个流程,尤其是风场数据,随着机组老化,特征之间的关系也会变化。
我的习惯:每次模型迭代后,把特征重要性排名和上次的对比一下。如果某个特征排名突然下降很多,大概率是数据质量出了问题,或者物理机理发生了变化。
公众号:蓝海资料掘金营,微信deep3321