VarianceThreshold默认阈值为0,仅剔除方差为0的特征;需设非零threshold才过滤低方差特征,且输入须为数值型,稀疏矩阵需防转密。

方差过滤 VarianceThreshold 为什么没筛掉低方差特征?
因为默认阈值是 0,只剔除完全不变的特征(方差为 0 的列)。实际数据里,很多特征方差极小但不为 0,比如某列 99% 是 0、1% 是 1,VarianceThreshold() 默认根本不会动它。
- 必须显式设
threshold=0.01这类非零值,才真正起过滤作用 - 注意:输入必须是数值型,类别型字段(如
'high'/'low')会报错,得先用OneHotEncoder或LabelEncoder转换 - 对稀疏矩阵支持好,但若用
fit_transform后再传给树模型,记得检查是否意外转成了密集数组——内存可能暴涨
SelectKBest 配 f_classif 报错 ValueError: Input X must be non-negative
这是 f_classif(用于分类任务的 F 检验)的硬性要求:所有特征值必须 ≥ 0。不是数据有负数就一定错,而是它内部调用的 scipy 函数明确拒绝负值。
- 常见场景:你用了标准化(
StandardScaler),结果把特征中心化到均值为 0,自然出现负数 - 解法不是“去掉标准化”,而是换评估器:
mutual_info_classif不限制正负,或改用SelectPercentile+chi2(但后者仍要求非负,仅适用于计数类特征) - 注意
f_classif和f_regression名字像、用法像,但任务类型不能混——前者只接受整数/字符串标签,后者才吃浮点目标值
用 RFECV 包装法选特征,结果每次运行都不一样
核心原因是默认的 estimator(如 RandomForestClassifier)本身带随机性,且 RFECV 内部做交叉验证时也涉及数据打乱。
- 固定随机种子:给
estimator加random_state=42,同时在RFECV里传cv=StratifiedKFold(n_splits=5, shuffle=True, random_state=42) - 别省计算:默认
step=1是逐个剔特征,慢但稳定;设成step=0.1(按比例删)会跳过中间状态,路径不可复现 - 小心过拟合信号:如果 CV 得分曲线在某个特征数后开始震荡上升,不是模型变强了,很可能是验证集太小或随机性干扰,建议加大
cv折数
树模型 feature_importances_ 为啥和实际业务直觉冲突?
树模型(如 RandomForest、XGBoost)输出的重要性,本质是基于分裂增益的统计量,不反映变量对目标的独立影响,更不等价于回归系数的符号或量级。
立即学习“Python免费学习笔记(深入)”;
- 高度相关的特征会“争抢”重要性——比如
age和age_squared同时存在,其中一个得分可能虚高,另一个被压低 -
XGBoost默认用gain,但也可切到weight(分裂次数)或cover(覆盖样本数),三者排序常不一致,得看你想解释什么 - 单棵树的
feature_importances_噪声极大,务必用集成模型(≥ 100 棵树),且检查std是否远小于均值,否则这组重要性本身就不稳定
真实项目里,树的重要性只能当第一轮线索,真要确认某个特征是否该留,得结合部分依赖图(PartialDependenceDisplay)、SHAP 值,或者干脆做消融实验——删掉它,看线上指标掉多少。










