4. 数据探查与质量检查:使用SQL检查空值、重复值、异常值,确保特征计算的准确性
在催收特征工程中,原始数据表的脏数据会直接导致特征计算偏差,进而影响催收策略的精准度。本章聚焦于使用SQL对原始数据进行系统性探查与质量检查,重点覆盖空值、重复值和异常值三大维度。只有通过严格的数据质量关卡,后续的特征计算才有可靠的基石。
4.1 数据质量检查的三维框架
数据质量检查并非一次性操作,而是贯穿特征计算全流程的校验环节。以下表格概括了三个维度的检查目标与典型SQL方法:
| 检查维度 | 检查目标 | 典型SQL方法 | 催收场景示例 |
|---|---|---|---|
| 空值检查 | 识别字段缺失比例,判断填充策略 | COUNT(*) vs COUNT(column)、SUM(CASE WHEN ISNULL) |
联系人电话为空,影响催收触达率特征 |
| 重复值检查 | 发现重复记录,避免特征聚合失真 | ROW_NUMBER() OVER(PARTITION BY)、GROUP BY + HAVING COUNT>1 |
同一笔案件被重复录入,导致逾期天数翻倍 |
| 异常值检查 | 识别超出业务合理范围的数据点 | PERCENTILE_CONT、WHERE value > 上限、Z-Score |
逾期金额为负数或超过授信额度10倍 |
4.2 空值检查:识别缺失模式
空值在催收数据中普遍存在,例如客户未填写第二联系人、催收员未记录通话时长等。空值检查的核心是量化缺失比例并判断缺失是否随机。
4.2.1 单字段空值率计算
以下SQL计算催收案件表中关键字段的空值率:
-- 计算各字段空值数量与空值率
SELECT
COUNT(*) AS total_records,
COUNT(contact_phone) AS phone_filled,
COUNT(second_contact_name) AS second_name_filled,
COUNT(collection_remark) AS remark_filled,
ROUND(100.0 * (COUNT(*) - COUNT(contact_phone)) / COUNT(*), 2) AS phone_null_rate,
ROUND(100.0 * (COUNT(*) - COUNT(second_contact_name)) / COUNT(*), 2) AS second_name_null_rate,
ROUND(100.0 * (COUNT(*) - COUNT(collection_remark)) / COUNT(*), 2) AS remark_null_rate
FROM collection_case;
4.2.2 多条件空值组合分析
有时空值并非孤立存在,多个字段同时缺失可能暗示数据源问题:
-- 查找联系人电话与地址同时为空的案件
SELECT
COUNT(*) AS both_null_count,
ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM collection_case), 2) AS both_null_rate
FROM collection_case
WHERE contact_phone IS NULL
AND contact_address IS NULL;
策略提示: 若某字段空值率超过30%,需评估该字段是否适合直接用于特征计算。对于催收场景,联系人电话空值率超过5%时应触发预警,因为该字段直接影响催收触达率特征。
4.3 重复值检查:消除冗余记录
重复数据通常源于系统重复导入、接口重试或人工误操作。重复记录会导致聚合类特征(如逾期次数、催收次数)被高估。
4.3.1 基于业务主键的重复检测
以案件ID和客户ID为联合主键,查找重复记录:
-- 查找重复的案件记录
SELECT
case_id,
customer_id,
COUNT(*) AS dup_count
FROM collection_case
GROUP BY case_id, customer_id
HAVING COUNT(*) > 1
ORDER BY dup_count DESC;
4.3.2 使用窗口函数标记重复行
当需要保留一条记录并删除其余重复时,使用ROW_NUMBER()进行标记:
-- 标记重复行,保留最早创建的一条
SELECT
case_id,
customer_id,
create_time,
ROW_NUMBER() OVER (
PARTITION BY case_id, customer_id
ORDER BY create_time ASC
) AS rn
FROM collection_case
WHERE case_id IN (
SELECT case_id FROM collection_case
GROUP BY case_id, customer_id
HAVING COUNT(*) > 1
);
注意: 删除重复记录前,务必与业务方确认保留规则(如保留最早/最晚记录、保留催收状态最新的记录)。直接删除可能导致催收进度信息丢失。
4.4 异常值检查:识别业务不合理数据
异常值在催收数据中表现为超出业务常识的数值,例如逾期天数为负数、催收通话时长为0秒、逾期金额超过授信额度数倍等。
4.4.1 基于业务规则的异常值过滤
定义明确的业务阈值,直接筛选出异常记录:
-- 检查逾期金额异常:负数或超过授信额度1.5倍
SELECT
case_id,
overdue_amount,
credit_limit,
overdue_days
FROM collection_case
WHERE overdue_amount < 0
OR overdue_amount > credit_limit * 1.5;
4.4.2 基于统计分布的异常值检测
使用百分位数识别离群点,适用于无明确业务阈值的字段:
-- 计算催收通话时长的P1和P99百分位
WITH stats AS (
SELECT
PERCENTILE_CONT(0.01) WITHIN GROUP (ORDER BY call_duration_seconds) AS p1,
PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY call_duration_seconds) AS p99
FROM collection_call_log
)
SELECT
c.call_id,
c.call_duration_seconds,
CASE
WHEN c.call_duration_seconds < s.p1 THEN '过低异常'
WHEN c.call_duration_seconds > s.p99 THEN '过高异常'
ELSE '正常'
END AS anomaly_flag
FROM collection_call_log c
CROSS JOIN stats s
WHERE c.call_duration_seconds < s.p1
OR c.call_duration_seconds > s.p99;
4.5 质量检查结果汇总与决策
完成三个维度的检查后,需要将结果汇总为一份数据质量报告,并据此决定特征计算的策略:
- 空值处理: 缺失率 < 5% 直接删除;5%-30% 使用均值/中位数/业务默认值填充;> 30% 考虑剔除该字段或转为“是否缺失”的二值特征。
- 重复处理: 确认保留规则后删除冗余行,并在特征计算时使用
DISTINCT或窗口函数去重。 - 异常处理: 业务阈值明确的直接截断或标记;统计离群点可做封顶处理(Winsorize)或单独作为异常标签特征。
实战要点: 在催收特征计算中,空值填充建议优先使用业务默认值(如通话时长空值填充0),而非统计均值,因为均值可能掩盖催收员未作业的真实情况。异常值建议保留为独立特征(如“逾期金额是否异常”),而非直接删除,因为异常本身可能蕴含高违约风险信号。
4.6 自动化质量检查脚本模板
将上述检查逻辑封装为可复用的SQL脚本,便于在每次特征计算前自动执行:
-- ============================================
-- 数据质量检查自动化脚本(催收特征专用)
-- ============================================
-- 1. 空值检查
SELECT '空值检查' AS check_type,
'contact_phone' AS field_name,
ROUND(100.0 * SUM(CASE WHEN contact_phone IS NULL THEN 1 ELSE 0 END) / COUNT(*), 2) AS null_rate
FROM collection_case
UNION ALL
SELECT '空值检查', 'overdue_amount',
ROUND(100.0 * SUM(CASE WHEN overdue_amount IS NULL THEN 1 ELSE 0 END) / COUNT(*), 2)
FROM collection_case;
-- 2. 重复值检查
SELECT '重复值检查' AS check_type,
'case_id + customer_id' AS composite_key,
COUNT(*) - COUNT(DISTINCT case_id || '-' || customer_id) AS duplicate_count
FROM collection_case;
-- 3. 异常值检查
SELECT '异常值检查' AS check_type,
'overdue_amount' AS field_name,
COUNT(*) AS anomaly_count
FROM collection_case
WHERE overdue_amount < 0 OR overdue_amount > 1000000;
通过以上系统化的数据探查与质量检查流程,你能够确保进入特征计算环节的数据是干净、可靠且符合业务逻辑的。这是催收策略模型稳定运行的基石,也是数据分析师专业性的直接体现。