variancethreshold有时删不掉预期特征,因其按未归一化原始方差计算,不考虑目标变量或标准化;如99%为0、1%为100的列,方差达100,远超默认threshold=0.0而被保留。

为什么VarianceThreshold有时删不掉预期的特征
因为VarianceThreshold默认按「未归一化的原始方差」计算,而类别型特征(如0/1编码后的列)或稀疏数值特征(如大量0、少量1)的方差可能高于阈值,导致没被过滤。它只看每个特征自身的方差,不考虑目标变量,也不做标准化——所以如果某列是「99%为0、1%为100」,方差其实是 0.01 * 100² = 100,远超默认的threshold=0.0,结果保留了下来。
实操建议:
- 对二值特征,先用
np.var(X[:, i], ddof=0)手动验证单列方差,确认是否真低于阈值 - 若想按「非零比例」或「变异系数」过滤,
VarianceThreshold不适用,得自己写逻辑 - 注意输入必须是二维数组或DataFrame;传入
Series会报ValueError: Expected 2D array, got 1D array instead
VarianceThreshold的threshold参数到底怎么设
阈值是方差下限:方差 小于 该值的特征被移除。默认threshold=0.0,即只删全相同值的列(方差为0)。但实际中更常用非零值,比如:
- 过滤掉95%以上值相同的列:估算其方差上限 —— 若某列95%为0、5%为1,则方差 ≈
0.05 * (1 - 0.05)² + 0.95 * (0 - 0.05)² ≈ 0.0475,设threshold=0.05可覆盖这类情况 - 对标准化后的数据(均值0、标准差1),方差=1,此时
threshold=0.01相当于删标准差 - 慎用过小阈值(如
1e-5),浮点误差可能导致本该保留的列被误删
和StandardScaler一起用时顺序不能错
VarianceThreshold必须在缩放前使用。因为缩放(如StandardScaler)会把所有特征方差强行拉到≈1,再过VarianceThreshold就完全失效了——所有列方差都接近1,一个都删不掉。
正确流程:
from sklearn.feature_selection import VarianceThreshold from sklearn.preprocessing import StandardScaler <p>selector = VarianceThreshold(threshold=0.1) X_filtered = selector.fit_transform(X) # 先过滤</p><p>scaler = StandardScaler() X_scaled = scaler.fit_transform(X_filtered) # 再缩放</p>
常见错误:把StandardScaler放在前面,然后发现VarianceThreshold像没起作用一样。
DataFrame输入时列名丢失怎么办
VarianceThreshold.fit_transform()返回的是numpy.ndarray,原始DataFrame的列名会丢。如果你依赖列名做后续分析(比如看哪几列被删了),得手动恢复:
- 用
selector.get_support()获取布尔掩码:mask = selector.get_support(),然后df.columns[mask]就是保留的列名 - 或者封装成带列名保持的函数:
pd.DataFrame(X_filtered, columns=df.columns[mask], index=df.index) - 注意:别直接用
df.iloc[:, mask],因为mask是布尔数组,iloc不支持布尔索引列(会报错),得用df.loc[:, mask]
真正容易被忽略的点是:方差计算基于训练集统计量,但测试集不做方差重算——所以务必在fit_transform之后,对测试集只调用transform,否则可能因测试集某列方差偶然更低而漏删,造成训练/推理不一致。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











