刚开始学机器学习时,我也像大部分人 一样,有个很朴素的想法:特征越多,模型能学到的信息就越多,效果自然越好。 科技新闻。
"体重kg"和"体重斤"的相关系数是 1.0——完全冗余,一眼就能看出来。
还是上面的例子。假设我们的目标是预测"健康状况评分":
用相背景与起因
我们用 pandas 一行就能算出来:
文中封装的 class CorrelationSelector 和测试其使用方式的完整代码分享在网盘中:
总结起来大概有这几点:
用相事件经过
我现在一般默认用 0.95,最少也不低于 0.85。
实现的核心思想就是,如果两个特征之间高度相关,它们携带的信息大量重叠,只需保留其中一个。
一眼就能看出来——"体重(kg)"和"体重(斤)"完全就是同一个信息的不同表达方式。同时把它们喂给模型,模型不会学到任何新东西,反而会被干扰。
用相各方回应
真实场景里当然不会这么夸张,但本质是一样的。比如:
回过头来看,相关性特征选择这个技术真的很朴素,但越朴素的东西越容易被人忽略。
这个坑比较隐蔽。假设有三个特征 A、B、C:
用相影响分析
相关系数大家应该都见过,最常用的是 Pearson 相关系数,取值 -1 到 1:
颜色越深的格子,就越是"危险区域"——大概率存在冗余。看一眼热力图,你对哪些特征需要处理就心里有数了。
最后只剩下 A。但如果你仔细看,A 和 C 的相关性最高(0.98),也许应该删的是 A 而保留 C。
相关文件是:correlation_selector.py 和 test_correlation_selector.py。
我用一个特别直观的场景来解释。
如果"体重kg"和"体重斤"必须删一个,删哪个其实无所谓(反正信息完全一样)。
根据这个原理,实现的思路也特别直接,就三步:
但如果两个特征的相关系数是 0.96 而不是 1.0,它们就不完全相同了,这时候保留与目标变量更相关的那个,就更有意义。
Pearson 相关系数只能捕捉线性关系。如果两个特征之间是某种曲线关系(比如二次函数),Pearson 可能算出来接近 0,但它们其实是强相关的。
在跑选择器之前,可以先画一张相关系数热力图,对数据有个直观感受:
而保留哪个?取决于是否提供了目标变量 y :
如果真的很在意,可以用迭代式的方式:每次只删一个特征,然后重新计算相关矩阵,再来一轮。
答案就是相关性。这也是我们在机器学习训练之前消除"冗余特征"的实现原理。
https://url11.ctfile.com/d/45455611-166997307-d6d609?p=6872 (访问密码: 6872)
接下来就是设一个阈值。根据经验:
假设你要判断一个人胖不胖,你收集了这些指标:
我们需要注意:相关性高不等于冗余,只有"高度到几乎可替代"的程度才算冗余。
然后我就发现事情不太对劲了:
这些特征单独看都有意义,但放在一起就冗余了。
后来我才知道,这就是所谓的特征冗余问题。
上面那张表里,如果阈值设 0.95,那"体重kg"和"体重斤"这一对就被揪出来了。
而解决它的一个简单有效的方法,就是相关性分析。
假设我们有 5 个特征,算出来大概是这么一张表:
但这样计算量会大不少,一般没必要。
这种"贪心策略的连锁反应"在特征特别多的时候影响更大。不过说实话,在大多数实际场景下,这个问题影响不大——毕竟我们的目标不是找到"最优子集",而是去掉明显冗余的特征,让模型更干净。
找出冗余对之后,问题来了——删哪个?
我的测试结果如下:
一个原本 20 列的数据集,经常被我搞到七八十列。
这里有个很实用的策略:看谁跟目标变量(也就是你要预测的那个东西)更相关,留那个更有用的。
用法非常简单,三行搞定:
比如把阈值设成 0.7,心想"相关性超过 0.7 就算冗余了吧"。
完整的代码和使用方式见文末的分享链接。
我的做法: 如果对数据分布不太确定,我会换成 spearman 方法,它基于排序,能捕捉单调关系:
所以每次拿到数据,我就拼命往模型里塞特征——能算出来的统计量全加上,能衍生出来的比率全拼上。
结果一跑,将近一半的特征被删掉了,模型效果直接崩了。
理解了原理和思路之后,封装了一个工具类。核心逻辑是这样的:
0.8 的两个特征,各自还是有独立信息量的。
消除"冗余特征"之后,RMSE 显著降低。