4. 特征分层方法论:基于信息量(IV)的分层、基于缺失率的分层、基于稳定性(PSI)的分层
在风控特征工程中,特征分层是连接特征加工与模型训练的关键桥梁。合理的分层策略能显著提升样本抽样的代表性,并降低因特征分布偏移导致的模型衰减风险。本节系统阐述三种主流分层方法:信息量(IV)分层、缺失率分层与稳定性(PSI)分层,并给出在 Spark 环境下的实现要点。
4.1 基于信息量(IV)的分层
信息量(IV, Information Value)是衡量特征对二分类目标变量区分能力的经典指标。IV 值越高,特征对好坏样本的区分度越强。基于 IV 分层,旨在将特征按预测能力划分为不同层级,用于指导特征筛选与抽样权重分配。
IV 计算公式:
IV = Σ ( (Good_i / Good_total) - (Bad_i / Bad_total) ) * ln( (Good_i / Good_total) / (Bad_i / Bad_total) )
其中,Good_i 和 Bad_i 分别表示第 i 个分箱中好样本与坏样本的数量。
IV 分层阈值参考:
- IV < 0.02:无预测能力,建议剔除。
- 0.02 ≤ IV < 0.10:弱预测能力,可保留但需谨慎。
- 0.10 ≤ IV < 0.30:中等预测能力,常用特征。
- IV ≥ 0.30:强预测能力,核心特征。
在 Spark 中,可通过 groupBy 与聚合函数实现 IV 的分布式计算。以下为基于分箱后的 IV 计算代码片段:
import org.apache.spark.sql.functions._
// 假设 df 包含字段: feature_bin, label (1=坏, 0=好)
val ivDF = df.groupBy("feature_bin")
.agg(
sum(when(col("label") === 0, 1).otherwise(0)).alias("good_cnt"),
sum(when(col("label") === 1, 1).otherwise(0)).alias("bad_cnt")
)
.withColumn("good_dist", col("good_cnt") / sum("good_cnt").over())
.withColumn("bad_dist", col("bad_cnt") / sum("bad_cnt").over())
.withColumn("woe", log(col("good_dist") / col("bad_dist")))
.withColumn("iv_contrib", (col("good_dist") - col("bad_dist")) * col("woe"))
val totalIV = ivDF.agg(sum("iv_contrib")).first().getDouble(0)
4.2 基于缺失率的分层
缺失率是衡量特征数据完整性的核心指标。高缺失率特征可能引入噪声或偏差,低缺失率特征则更可靠。基于缺失率分层,有助于在抽样时对特征质量进行差异化处理,例如对高缺失率特征进行标记或填充策略调整。
| 缺失率区间 | 分层标签 | 推荐处理策略 |
|---|---|---|
| [0%, 5%) | 低缺失 | 直接使用,无需特殊处理 |
| [5%, 20%) | 中缺失 | 均值/中位数填充,或增加缺失指示列 |
| [20%, 50%) | 高缺失 | 优先使用模型预测填充,或考虑剔除 |
| [50%, 100%] | 极高缺失 | 建议剔除,或仅保留缺失指示列 |
Spark 中计算特征缺失率的典型实现:
import org.apache.spark.sql.functions._
// 计算每列缺失率
val missingRateDF = df.select(
df.columns.map(c =>
(sum(when(col(c).isNull || col(c) === "" || col(c).isNaN, 1).otherwise(0)) / count("*")).alias(s"${c}_missing_rate")
): _*
)
注意:缺失率分层应与业务含义结合。例如,某些风控特征(如“逾期天数”)的缺失可能代表“未逾期”,而非数据缺失,此时不应按常规缺失率处理。
4.3 基于稳定性(PSI)的分层
群体稳定性指标(PSI, Population Stability Index)用于衡量特征在时间维度上的分布偏移程度。PSI 越大,特征越不稳定,模型在跨时间样本上的表现越可能衰减。基于 PSI 分层,可识别出需要重点监控或重新建模的特征。
PSI 计算公式:
PSI = Σ ( (Actual_i / Actual_total) - (Expected_i / Expected_total) ) * ln( (Actual_i / Actual_total) / (Expected_i / Expected_total) )
其中,Actual 为当前样本分布,Expected 为基准样本分布。
| PSI 区间 | 分层标签 | 风控含义 |
|---|---|---|
| [0, 0.10) | 稳定 | 特征分布无显著变化,可继续使用 |
| [0.10, 0.25) | 轻度偏移 | 需关注,建议检查业务逻辑 |
| [0.25, +∞) | 严重偏移 | 特征已失效,需重新开发或剔除 |
Spark 中计算 PSI 的分布式实现:
import org.apache.spark.sql.functions._
// 假设 actualDF 为当前样本,expectedDF 为基准样本,均包含分箱字段 bin
val actualDist = actualDF.groupBy("bin").count().withColumnRenamed("count", "actual_cnt")
val expectedDist = expectedDF.groupBy("bin").count().withColumnRenamed("count", "expected_cnt")
val psiDF = actualDist.join(expectedDist, Seq("bin"), "outer")
.na.fill(0)
.withColumn("actual_pct", col("actual_cnt") / sum("actual_cnt").over())
.withColumn("expected_pct", col("expected_cnt") / sum("expected_cnt").over())
.withColumn("psi_contrib", (col("actual_pct") - col("expected_pct")) * log(col("actual_pct") / col("expected_pct")))
val totalPSI = psiDF.agg(sum("psi_contrib")).first().getDouble(0)
4.4 三种分层方法的综合对比
| 维度 | IV 分层 | 缺失率分层 | PSI 分层 |
|---|---|---|---|
| 核心目标 | 衡量预测能力 | 衡量数据完整性 | 衡量分布稳定性 |
| 计算依赖 | 需要标签(好坏样本) | 仅需特征自身 | 需要两个时间窗口的分布 |
| 分层输出 | 弱/中/强预测力 | 低/中/高/极高缺失 | 稳定/轻度偏移/严重偏移 |
| Spark 实现复杂度 | 中等(需分箱+聚合) | 低(简单聚合) | 中等(需跨数据集Join) |
| 在抽样中的应用 | 按IV权重分配抽样比例 | 对高缺失特征降权或标记 | 对不稳定特征进行分层校验 |
最佳实践建议:在风控特征工程中,推荐先进行缺失率分层清洗低质量特征,再通过 IV 分层筛选强预测特征,最后用 PSI 分层监控特征的跨时间稳定性。三层递进可形成完整的特征质量评估体系。