方差过滤必须用VarianceThreshold而非手动计算删除,因其严格保障fit/transform一致性:fit仅基于训练集确定删哪些列,transform对训练集和测试集执行完全相同的列裁剪,避免因手动操作导致测试集列数不匹配而报错。

方差过滤不是“计算方差”,而是用方差作为阈值筛掉低变异性特征——直接调用 VarianceThreshold,别自己算完再手动删。
为什么不能先用 np.var() 再手动 drop?
手动计算再筛选会破坏 fit/transform 的分离逻辑,导致训练集和测试集用不同列数,后续模型报错 ValueError: X has 5 features, but VarianceThreshold is expecting 7 features。Scikit-learn 的设计要求所有预处理必须封装成可复用的 transformer。
-
VarianceThreshold在fit()时只看训练集的各列方差,记住哪些列该删 -
transform()时对训练集/测试集做**完全一致的列裁剪**,不重新计算方差 - 若用
np.var(X_train, axis=0)手动找var 的索引,再用X_train[:, mask],测试集就得重复一遍——但测试集方差可能略高或略低,mask 就不一致
VarianceThreshold 的 threshold 参数怎么设?
它默认是 threshold=0.0,即只删全相同(方差为 0)的列。实际中多数二值特征(如 one-hot 后的类别列)或稀疏数值特征需要更宽松的阈值。
- 对标准化后的特征(均值 0、标准差 1),
threshold=0.01表示删掉标准差 - 对原始数值特征,建议先标准化再过滤,否则量纲差异会让方差失去可比性
- 对二值特征(0/1),方差 =
p*(1-p),最大值 0.25(当 p=0.5),所以threshold=0.05大致对应保留出现频率在 ~20%–80% 之间的特征
如何保留被过滤掉的列名?
VarianceThreshold 默认返回 numpy array,列名丢失。要保留名称,得配合 pandas 和自定义逻辑:
from sklearn.feature_selection import VarianceThreshold import pandas as pd <p>X = pd.DataFrame([[0, 1, 2], [0, 1, 1], [0, 1, 0]]) selector = VarianceThreshold(threshold=0.5) X_filtered = selector.fit_transform(X)</p><h1>获取被保留的列名</h1><p>kept_mask = selector.get_support() # 返回布尔数组 kept_columns = X.columns[kept_mask].tolist() # ['1', '2'],注意:原列名是字符串数字 </p>
-
selector.get_support()必须在fit()或fit_transform()之后调用 - 别用
selector.get_feature_names_out()—— 它在旧版 sklearn 中不存在,新版虽有但仅支持传入原始列名列表,且不处理缺失列名场景 - 如果原始
X是 DataFrame,fit_transform()输出仍是 ndarray;想保持 DataFrame,得手动重建:pd.DataFrame(X_filtered, columns=kept_columns, index=X.index)
真正容易被忽略的是:方差过滤对异常值极度敏感——单个离群点就能把某列方差拉高,让它逃过过滤;而缺失值未填充时,VarianceThreshold 会直接报错 ValueError: Input contains NaN,它不做任何插补。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











