3. 单变量特征选择(方差过滤):方差阈值法
方差阈值法(Variance Threshold)是单变量特征筛选中最基础、最快速的方法。它不依赖目标变量,仅通过特征自身的离散程度来判断是否保留,属于典型的无监督过滤式特征选择。
3.1 核心原理
方差衡量一组数据的离散程度。对于特征 \(X\),其方差计算公式为:
\(\text{Var}(X) = \frac{1}{n-1} \sum_{i=1}^{n} (x_i - \bar{x})^2\)
方差越小,说明该特征的所有样本取值越接近常数;方差为零时,特征取值完全一致,对模型无任何区分能力。方差阈值法通过设定一个最小方差阈值,自动剔除方差低于该阈值的特征。
关键认知: 方差过滤只关心特征自身的波动大小,不关心特征与标签的相关性。一个方差很大的特征可能是噪声,也可能是有用信号;方差很小的特征几乎一定是冗余或无效的。
3.2 适用场景与局限性
| 维度 | 说明 |
|---|---|
| 适用场景 |
|
| 局限性 |
|
⚠ 常见陷阱: 对二值特征(0/1)直接计算原始方差时,方差 = p(1-p),其中 p 为 1 的比例。当 p 接近 0 或 1 时方差很小,但这类特征可能对模型有决定性作用。建议对二值特征单独设置较低的阈值,或结合频次过滤。
3.3 方差阈值法的决策流程
下图展示了方差阈值法在特征筛选流水线中的标准执行步骤:
3.4 Python 实现:VarianceThreshold
scikit-learn 提供了 VarianceThreshold 类,一行代码即可完成方差过滤。以下为完整实现示例:
import numpy as np
import pandas as pd
from sklearn.feature_selection import VarianceThreshold
from sklearn.preprocessing import StandardScaler
# 1. 构造示例数据(包含低方差特征)
np.random.seed(42)
n_samples = 1000
data = pd.DataFrame({
'feature_1': np.random.randn(n_samples), # 正常方差 ≈ 1.0
'feature_2': np.random.randn(n_samples) * 0.1, # 低方差 ≈ 0.01
'feature_3': np.random.randn(n_samples) * 0.01, # 极低方差 ≈ 0.0001
'feature_4': np.random.randint(0, 2, n_samples), # 二值特征,方差 ≈ 0.25
'feature_5': np.ones(n_samples) * 42, # 零方差(常数)
})
print("原始特征方差:")
print(data.var().round(6))
# 2. 标准化(重要!消除量纲影响)
scaler = StandardScaler()
data_scaled = pd.DataFrame(
scaler.fit_transform(data),
columns=data.columns
)
# 3. 方差过滤:保留方差 > 0.1 的特征
selector = VarianceThreshold(threshold=0.1)
data_selected = selector.fit_transform(data_scaled)
# 4. 查看结果
selected_mask = selector.get_support()
selected_features = data.columns[selected_mask]
removed_features = data.columns[~selected_mask]
print(f"\n保留特征 ({len(selected_features)} 个): {list(selected_features)}")
print(f"剔除特征 ({len(removed_features)} 个): {list(removed_features)}")
# 5. 输出过滤后的数据形状
print(f"\n过滤前形状: {data_scaled.shape}")
print(f"过滤后形状: {data_selected.shape}")
3.5 阈值设定策略
阈值的选择直接影响过滤效果。下表总结了不同场景下的推荐做法:
| 数据类型 | 推荐阈值 | 说明 |
|---|---|---|
| 标准化后的连续特征 | 0.01 ~ 0.1 | 标准化后方差为 1,低于 0.01 的特征几乎无波动 |
| 二值特征 (0/1) | 0.8 × p(1-p) 或 0.01 | 保留至少 5% 样本出现 1 的特征(p > 0.05) |
| 归一化到 [0,1] 的特征 | 0.005 ~ 0.05 | 归一化后方差上限为 0.25,阈值不宜过高 |
| 高维稀疏数据 | 0.001 ~ 0.01 | 稀疏矩阵方差普遍偏小,需降低阈值 |
💡 实用技巧: 如果不确定阈值,可以先计算所有特征的方差分布,取方差排序后第 5~10 百分位的值作为阈值。或者使用
selector.fit_transform(data) 默认阈值 0,仅剔除零方差特征,再结合业务判断。
3.6 方差过滤与后续特征选择的衔接
方差阈值法通常作为特征筛选的第一道关卡,其输出结果会传递给更精细的选择方法。下图展示了在完整特征工程流水线中的位置:
3.7 注意事项与最佳实践
- 先标准化,后过滤: 方差对量纲敏感,不同尺度的特征方差不可比。务必先进行 Z-score 标准化或 Min-Max 归一化。
- 分类型特征单独处理: 对于类别型特征,先进行独热编码,再对每个二值列进行方差过滤。可考虑结合频次过滤(剔除出现次数过少的类别)。
- 不要过度过滤: 方差阈值过高可能导致丢失有用特征。建议从低阈值开始,逐步调高并观察模型性能变化。
- 与业务规则结合: 某些低方差特征在业务上具有特殊意义(如“是否死亡”),即使方差很小也应保留。
- 管道化集成: 使用
sklearn.pipeline.Pipeline将 VarianceThreshold 与后续模型串联,避免数据泄露。
# 管道化示例:方差过滤 + 逻辑回归
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
pipeline = Pipeline([
('scaler', StandardScaler()),
('var_filter', VarianceThreshold(threshold=0.05)),
('classifier', LogisticRegression())
])
pipeline.fit(X_train, y_train)
print(f"过滤后特征数: {pipeline.named_steps['var_filter'].n_features_in_}")
print(f"模型准确率: {pipeline.score(X_test, y_test):.4f}")