SQL 在风控样本校验中的角色

在风控模型开发与监控的生命周期中,样本偏差校验是确保模型稳定性和预测能力的关键环节。SQL 凭借其对结构化数据的高效处理能力,成为连接原始数据仓库与风控校验逻辑的核心工具。本章将系统阐述 SQL 在风控样本校验中的独特优势、典型数据仓库与风控表结构设计,以及标准化的 SQL 校验流程。

2.1 SQL 在风控样本校验中的核心优势

相比于 Python、R 等通用分析工具,SQL 在风控样本校验场景中具备以下不可替代的优势:

优势维度 具体说明 风控场景示例
数据原生性 风控数据通常存储在数据仓库或数据湖中,SQL 无需数据迁移即可直接查询 直接从 Hive/ClickHouse 中提取 3 个月逾期样本
大规模处理能力 SQL 引擎(如 SparkSQL、Presto)可分布式处理亿级数据,远超单机内存限制 对 5 亿条交易流水进行时间窗口切片
集合运算简洁性 通过 JOIN、UNION、EXCEPT 等操作快速完成样本交叉验证 校验训练集与 OOT 时间段的分布一致性
可审计与可复现 SQL 脚本天然具备版本控制能力,便于风控合规审计 保留每次校验的 SQL 快照用于监管检查
与调度系统集成 SQL 可直接嵌入 Airflow、DolphinScheduler 等任务流 每日凌晨自动执行样本偏差监控脚本

关键认知:SQL 在风控校验中的角色不是替代统计建模工具,而是作为数据准备与偏差量化的第一道关卡。80% 的样本偏差问题可以通过 5~10 行 SQL 聚合语句发现。

2.2 数据仓库与风控表结构设计

风控样本偏差校验依赖清晰的数据分层与表结构设计。典型的风控数据仓库采用 ODS → DWD → DWS → ADS 四层架构,其中与样本校验直接相关的核心表包括:

表命名规范建议:采用 分层_主题_业务_时间粒度 格式,例如 dws_risk_loan_di 表示风险主题下的贷款明细日表。

2.2.1 核心风控表结构清单

表名(示例) 分层 核心字段 校验用途
dwd_risk_loan_apply_di DWD apply_id, user_id, apply_time, loan_amt, term, product_cd 申请样本量、时间分布校验
dws_risk_user_profile_di DWS user_id, age, gender, income_level, credit_score, hist_overdue_cnt 用户特征分布偏差校验
ads_risk_model_sample_df ADS sample_id, model_ver, sample_type, feature_json, label, weight 建模样本标签与权重校验
dwd_risk_performance_di DWD loan_id, perf_date, ovd_status, ovd_days, recovery_amt 表现期标签稳定性校验
ads_risk_psi_monitor_df ADS monitor_date, feature_name, psi_value, base_dist, curr_dist PSI 群体稳定性指标计算

2.2.2 风控数据仓库分层架构

下图展示了风控数据仓库的分层结构及各层在样本校验中的职责:

风控数据仓库分层架构与样本校验职责 ODS 源数据层 原始申请流水、征信报告、交易日志(保留全量历史) DWD 明细数据层 数据清洗、去重、字段标准化、时间切片(校验样本量、时间窗口) DWS 汇总数据层 用户画像宽表、特征衍生、统计指标(校验特征分布、PSI) ADS 应用数据层 建模样本表、PSI 监控表、校验结果报表(输出校验结论) 数据加工深度递增

常见陷阱:许多团队直接在 ODS 层进行样本校验,导致数据质量问题(重复、空值、时间戳异常)污染校验结果。务必在 DWD 层完成标准化清洗后再执行偏差分析。

2.3 SQL 校验的基本流程

标准化的 SQL 样本偏差校验流程包含 5 个核心步骤,覆盖从数据接入到结果输出的完整链路:

2.3.1 流程总览

SQL 风控样本偏差校验五步流程 步骤 1:数据接入 从 ODS/DWD 提取原始样本 步骤 2:质量清洗 去重、空值填充、异常过滤 步骤 3:维度统计 时间/特征/标签分布 步骤 4:偏差量化 PSI 计算、分布差异检验、统计显著性评估 步骤 5:结果输出 写入 ADS 校验结果表、触发告警或阻断 💡 每个步骤对应 1~3 条核心 SQL 语句,整体流程可在 10 分钟内完成百万级样本校验

2.3.2 各步骤核心 SQL 示例

步骤 1:数据接入 — 从 DWD 层提取训练集与 OOT 样本:

-- 训练集:2024年1月~6月申请样本
CREATE TABLE temp_train_sample AS
SELECT apply_id, user_id, apply_time, loan_amt, term
FROM dwd_risk_loan_apply_di
WHERE apply_time >= '2024-01-01' AND apply_time < '2024-07-01'
  AND is_valid = 1;

-- OOT 集:2024年7月~9月申请样本
CREATE TABLE temp_oot_sample AS
SELECT apply_id, user_id, apply_time, loan_amt, term
FROM dwd_risk_loan_apply_di
WHERE apply_time >= '2024-07-01' AND apply_time < '2024-10-01'
  AND is_valid = 1;

步骤 2:质量清洗 — 检查并处理关键字段的空值与异常:

-- 空值检测
SELECT 'train' AS sample_type,
       COUNT(*) AS total_cnt,
       SUM(CASE WHEN loan_amt IS NULL THEN 1 ELSE 0 END) AS null_loan_amt,
       SUM(CASE WHEN term <= 0 THEN 1 ELSE 0 END) AS invalid_term
FROM temp_train_sample
UNION ALL
SELECT 'oot' AS sample_type,
       COUNT(*),
       SUM(CASE WHEN loan_amt IS NULL THEN 1 ELSE 0 END),
       SUM(CASE WHEN term <= 0 THEN 1 ELSE 0 END)
FROM temp_oot_sample;

步骤 3:维度统计 — 按时间粒度统计样本量分布:

-- 按月统计训练集与 OOT 样本量
SELECT DATE_FORMAT(apply_time, 'yyyy-MM') AS month,
       COUNT(*) AS sample_cnt
FROM temp_train_sample
GROUP BY DATE_FORMAT(apply_time, 'yyyy-MM')
ORDER BY month;

步骤 4:偏差量化 — 计算特征 PSI(群体稳定性指标):

-- 以 loan_amt 分箱为例计算 PSI
WITH base_dist AS (
  SELECT CASE WHEN loan_amt < 5000 THEN '0-5k'
              WHEN loan_amt < 20000 THEN '5k-20k'
              ELSE '20k+' END AS bucket,
         COUNT(*) AS base_cnt
  FROM temp_train_sample
  GROUP BY CASE WHEN loan_amt < 5000 THEN '0-5k'
                WHEN loan_amt < 20000 THEN '5k-20k'
                ELSE '20k+' END
),
curr_dist AS (
  SELECT CASE WHEN loan_amt < 5000 THEN '0-5k'
              WHEN loan_amt < 20000 THEN '5k-20k'
              ELSE '20k+' END AS bucket,
         COUNT(*) AS curr_cnt
  FROM temp_oot_sample
  GROUP BY CASE WHEN loan_amt < 5000 THEN '0-5k'
                WHEN loan_amt < 20000 THEN '5k-20k'
                ELSE '20k+' END
)
SELECT b.bucket,
       b.base_cnt / SUM(b.base_cnt) OVER() AS base_pct,
       c.curr_cnt / SUM(c.curr_cnt) OVER() AS curr_pct,
       (b.base_cnt / SUM(b.base_cnt) OVER() - c.curr_cnt / SUM(c.curr_cnt) OVER())
       * LN(b.base_cnt / SUM(b.base_cnt) OVER() / NULLIF(c.curr_cnt / SUM(c.curr_cnt) OVER(), 0)) AS psi_component
FROM base_dist b
JOIN curr_dist c ON b.bucket = c.bucket;

步骤 5:结果输出 — 将校验结果写入 ADS 监控表:

INSERT INTO ads_risk_psi_monitor_df
(monitor_date, feature_name, psi_value, base_period, curr_period, alert_flag)
SELECT CURRENT_DATE AS monitor_date,
       'loan_amt' AS feature_name,
       ROUND(SUM(psi_component), 6) AS psi_value,
       '2024H1' AS base_period,
       '2024Q3' AS curr_period,
       CASE WHEN SUM(psi_component) > 0.1 THEN 1 ELSE 0 END AS alert_flag
FROM (
  -- 上述 PSI 计算子查询
) t;

流程要点总结:SQL 校验流程的核心在于 标准化 与 可重复。建议将上述 5 步封装为存储过程或 SQL 模板,每次模型迭代或数据更新时自动触发执行,形成持续监控闭环。

2.4 本章小结

  • SQL 优势:数据原生、大规模处理、集合运算简洁、可审计、易集成,是风控样本校验的首选工具。
  • 表结构设计:遵循 ODS→DWD→DWS→ADS 分层,每层承担不同的校验职责,核心表包括申请明细、用户画像、建模样本、表现期标签和 PSI 监控表。
  • 校验流程:数据接入 → 质量清洗 → 维度统计 → 偏差量化 → 结果输出,5 步闭环确保样本偏差可发现、可量化、可告警。