第4章 特征选择与维度控制
4.1 概述
在机会评分模型开发中,初始特征空间通常包含数十到数百个变量,其中大量变量是噪声、冗余或弱相关的。特征选择与维度控制的目标是在保证预测能力的前提下,剔除无效变量、降低过拟合风险、提升模型稳定性和可解释性。本章将依次介绍四种主流方法:IV值筛选、相关性剪枝、LASSO正则化以及前向/后向选择,并给出组合使用的最佳实践。
4.2 IV值筛选(信息量)
IV(Information Value) 衡量单个自变量对二元目标变量的区分能力。在信用评分领域,IV值常按以下区间判断:
| IV 区间 | 预测力 | 建议 |
|---|---|---|
| < 0.02 | 极弱 | 剔除 |
| 0.02 – 0.10 | 弱 | 可考虑剔除 |
| 0.10 – 0.30 | 中等 | 保留 |
| 0.30 – 0.50 | 强 | 重点保留 |
| > 0.50 | 极强但可能过拟合 | 需结合业务检验 |
实现要点: IV计算要求变量先进行分箱(WOE转化)。确保箱内样本数不少于总样本的5%,避免统计不稳定。
# Python 示例:计算单个变量IV
import pandas as pd
import numpy as np
def calc_iv(x, y, bins=10):
df = pd.DataFrame({'x': x, 'y': y})
df['bin'] = pd.qcut(df['x'], q=bins, duplicates='drop')
grouped = df.groupby('bin', observed=False)['y'].agg(['count', 'sum'])
grouped['event'] = grouped['sum']
grouped['non_event'] = grouped['count'] - grouped['sum']
total_event = grouped['event'].sum()
total_non_event = grouped['non_event'].sum()
grouped['event_rate'] = grouped['event'] / total_event
grouped['non_event_rate'] = grouped['non_event'] / total_non_event
grouped['woe'] = np.log(grouped['event_rate'] / grouped['non_event_rate'])
grouped['iv'] = (grouped['event_rate'] - grouped['non_event_rate']) * grouped['woe']
return grouped['iv'].sum()
4.3 相关性剪枝
剔除IV筛选后,特征之间仍可能存在高度相关(如 Pearson |r| > 0.7),导致多重共线性。剪枝策略:
- 计算特征相关矩阵,通常取绝对值。
- 对每一对高相关特征,保留 IV 较高(或业务重要性更高)的一方。
- 迭代直到无高相关对。
# 相关性剪枝示意:保留IV较大的特征
def prune_corr(x, y, threshold=0.7):
import pandas as pd
iv_scores = {col: calc_iv(x[col], y) for col in x.columns}
corr_matrix = x.corr().abs()
upper_tri = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(bool))
to_drop = set()
for col in upper_tri.columns:
high_corr = upper_tri[upper_tri[col] > threshold].index.tolist()
for hc in high_corr:
if iv_scores[col] < iv_scores[hc]:
to_drop.add(col)
else:
to_drop.add(hc)
return x.drop(columns=list(to_drop))
4.4 LASSO正则化
LASSO (L1) 通过在损失函数中加入权重绝对值之和的惩罚项,自动将不重要变量的系数压缩为零。关键参数 λ(或 sklearn 中的 C 的倒数)控制稀疏度。通常通过交叉验证选择最优 λ。LASSO 适用于高维稀疏场景,但若特征间高度相关,它可能随机选择一组。
# 使用 sklearn LogisticRegression 的 L1 惩罚
from sklearn.linear_model import LogisticRegressionCV
model = LogisticRegressionCV(
Cs=np.logspace(-3, 2, 20),
penalty='l1',
solver='saga', # 支持 L1 的求解器
cv=5,
scoring='roc_auc',
max_iter=2000,
random_state=42
)
model.fit(X_train, y_train)
selected = X_train.columns[model.coef_.flatten() != 0].tolist()
print(f"LASSO 保留特征数: {len(selected)}")
4.5 前向/后向选择
逐步回归的贪心版:
- 前向选择:从空集开始,每一步加入使 AIC/BIC 或 AUC 提升最大的特征,直到无显著改善。
- 后向选择:从全特征开始,每一步剔除重要性最弱的特征。
- 双向选择:结合两者,每次操作后可重新评估已选/已剔变量。
受限于计算量,当特征数 > 50 时推荐先使用前向或与 LASSO 结合。
# 前向选择示例(基于 AUC 增量)
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
def forward_selection(X, y, max_features=10):
selected = []
remaining = list(X.columns)
best_score = 0
while len(selected) < max_features and remaining:
scores = {}
for col in remaining:
cols_test = selected + [col]
m = LogisticRegression(max_iter=1000)
m.fit(X[cols_test], y)
scores[col] = roc_auc_score(y, m.predict_proba(X[cols_test])[:,1])
best_col = max(scores, key=scores.get)
if scores[best_col] > best_score:
best_score = scores[best_col]
selected.append(best_col)
remaining.remove(best_col)
else:
break
return selected
4.6 方法对比与选择策略
| 方法 | 核心原理 | 适用场景 | 输出形式 | 计算代价 |
|---|---|---|---|---|
| IV 筛选 | 单变量条件熵 | 大样本、低基数变量 | IV 值排序列表 | 低 |
| 相关性剪枝 | 线性相关系数 | 任意规模,减少多重共线性 | 剔除高相关对 | 中 |
| LASSO 正则化 | L1 惩罚 | 高维(p > n)、稀疏解 | 非零系数集合 | 中–高(需CV) |
| 前向/后向选择 | 贪心逐步搜索 | 特征 < 50,需要可解释性 | 有序特征列表 | 高(尤其后向) |
常见误区: 不要将 IV 筛选和相关性剪枝顺序颠倒。先做 IV 剔除弱变量,再做冗余剪枝,可减少后续 LASSO/逐步选择的搜索空间,同时避免“弱但独立”的特征被误删。
4.7 调试与评估
- IV 稳定性:在训练集和 OOT 样本上分别计算 IV,若差异 > 20%,说明变量分布不稳定,考虑剔除。
- LASSO 路径图:绘制不同 λ 下系数变化曲线,帮助理解哪些变量率先被压缩至零。
- 交叉验证 AUC:每次特征选择迭代后,使用简单模型(如 Logistic Regression)评估交叉验证 AUC,防止过拟合。
- 特征稳定性指数(PSI):对最终选择的特征集计算 PSI,检查整体分布漂移。
4.8 常见性能瓶颈与稳定性提升技巧
- 瓶颈1: IV 分箱过多导致过拟合。解决方法:限制最小箱数(min_samples=20),或使用单调分箱。
- 瓶颈2: LASSO 在强相关特征组中不稳定。使用
group lasso或先做相关性剪枝。 - 瓶颈3: 前向选择耗时且易过拟合。可在每步加入特征后执行 5 折 CV,而不是使用训练集 AUC。
- 稳定性技巧: 对原始特征做多次随机抽样,重复执行特征选择,保留出现频率 > 80% 的特征(Bootstrap 聚合)。
# 稳定性特征选择示例:Bootstrap 筛选 50 次
from sklearn.utils import resample
stable_features = {}
for i in range(50):
X_boot, y_boot = resample(X_train, y_train, random_state=i)
sel = forward_selection(X_boot, y_boot, max_features=15)
for f in sel:
stable_features[f] = stable_features.get(f, 0) + 1
final_features = [f for f, cnt in stable_features.items() if cnt >= 40] # 80% 标准
print(f"稳定特征: {final_features}")
4.9 本章小结
特征选择绝非一次性操作。推荐的标准流程为:IV筛选 → 相关性剪枝 → LASSO → 前向/后向精炼。每一步都应辅以业务验算和交叉验证,确保选出的特征既有统计显著性又有业务可解释性。通过本章的方法,可将原始上百维特征压缩至 10–30 维核心变量,显著提升模型鲁棒性与迭代效率。