3、风控特征工程:特征分类、特征构建、特征存储、特征监控
特征工程,说白了就是风控系统的“食材准备间”。
模型再牛,算法再先进,喂进去的特征是垃圾,出来的结果就是垃圾。我见过太多团队,花三个月调模型参数,结果一查,特征里居然有空值没处理干净。嗯,这种事,一次就够了。
3.1 特征分类:先分清楚再动手
我个人习惯把特征分成三大类。这样设计存储和计算的时候,思路会清晰很多。
| 特征类型 | 定义 | 典型例子 | 更新频率 |
|---|---|---|---|
| 静态特征 | 基本不变的用户属性 | 性别、注册时间、身份证归属地 | 一次性或低频 |
| 动态特征 | 随时间变化的行为数据 | 近7天登录次数、近30天交易金额 | 实时或准实时 |
| 衍生特征 | 基于原始数据加工计算 | 设备指纹、关系网络密度、多头借贷数 | 按需计算 |
核心原则:静态特征用宽表存,动态特征用时序存,衍生特征用特征服务实时算。千万别混在一起,否则后面维护成本会让你崩溃。
3.2 特征构建:从原始数据到高价值特征
特征构建是风控工程师的核心手艺。我刚开始做的时候,也踩过不少坑。
3.2.1 时间窗口特征
这是风控里最常用的。比如“过去7天申请次数”。
为什么用7天?不是5天也不是10天?
我在项目中遇到过,某现金贷产品,用户从注册到申请平均间隔是6.8天。所以7天窗口刚好能覆盖一个完整的行为周期。你想想看,如果窗口设成3天,很多正常用户的行为就抓不到,模型会误判。
-- 示例:计算近7天申请次数
SELECT user_id,
COUNT(*) AS apply_cnt_7d
FROM event_log
WHERE event_type = 'apply'
AND event_time >= NOW() - INTERVAL 7 DAY
GROUP BY user_id;
避坑指南:我曾经犯过一个低级错误——直接用当前时间计算窗口特征。结果线上和离线数据对不上。后来我改成用“事件发生时间”作为基准,才彻底解决。
3.2.2 比率与聚合特征
单一维度的特征往往不够。比如“申请次数”本身,不如“申请通过率”有区分度。
- 比率特征:通过率、逾期率、设备关联账户数
- 聚合统计:最大值、最小值、均值、标准差、分位数
- 序列特征:行为间隔、行为顺序、行为模式
举个例子。一个用户一天内申请了5次,每次间隔不到10分钟。这明显是机器行为。如果只看“申请次数”,可能只是觉得有点多。但加上“申请间隔标准差”,模型就能识别出这种异常模式。
3.2.3 图特征
这是高阶玩法。用户之间通过设备、IP、手机号等形成关系网络。
# 示例:计算用户的二度关联风险节点数
def get_second_degree_risk_nodes(user_id, graph, depth=2):
visited = set()
queue = [(user_id, 0)]
risk_count = 0
while queue:
node, d = queue.pop(0)
if d > depth:
break
if node in visited:
continue
visited.add(node)
if graph.nodes[node].get('is_risk', False):
risk_count += 1
for neighbor in graph.neighbors(node):
if neighbor not in visited:
queue.append((neighbor, d+1))
return risk_count
我记得有一次,一个团伙用200多个手机号申请贷款,每个号都换了设备。但图特征一跑,发现这些号都共用同一个WiFi MAC地址。嗯,图特征就是这么好用。
3.3 特征存储:选对工具,事半功倍
特征存储不是随便找个数据库就行的。不同特征有不同的存储需求。
| 存储类型 | 适用特征 | 推荐技术 | 关键指标 |
|---|---|---|---|
| 在线特征存储 | 实时决策需要的特征 | Redis、HBase | P99延迟 < 10ms |
| 离线特征存储 | 模型训练、批量分析 | Hive、ClickHouse | 高吞吐、低成本 |
| 特征元数据存储 | 特征定义、版本、血缘 | MySQL、Neo4j | 强一致性、可追溯 |
注意:在线特征存储一定要做缓存降级。我曾经遇到Redis集群宕机,结果所有风控请求都超时,业务直接停摆。后来加了本地缓存+降级策略,才稳住。
3.4 特征监控:别等出事了再后悔
特征监控是风控系统的“体检中心”。没有监控,你根本不知道特征什么时候坏了。
3.4.1 监控什么
- 特征覆盖率:是不是有大量用户特征缺失?
- 特征分布漂移:均值、方差有没有突然变化?
- 特征时效性:特征是不是过期了?
- 特征一致性:在线和离线算出来的值是否一致?
3.4.2 怎么监控
我个人习惯用PSI(群体稳定性指标)来监控特征分布漂移。
# 示例:计算PSI
def calculate_psi(expected, actual, bins=10):
# 将数据分箱
expected_hist, _ = np.histogram(expected, bins=bins, range=(0,1))
actual_hist, _ = np.histogram(actual, bins=bins, range=(0,1))
# 转换为比例
expected_pct = expected_hist / len(expected)
actual_pct = actual_hist / len(actual)
# 计算PSI
psi = 0
for e, a in zip(expected_pct, actual_pct):
if e == 0:
e = 0.0001
if a == 0:
a = 0.0001
psi += (a - e) * np.log(a / e)
return psi
PSI超过0.1就要报警。超过0.25,基本可以确定特征出了问题。
我的经验:特征监控的报警阈值不要设太死。我刚开始设了0.05,结果每天几百条报警,全是误报。后来调到0.1,再配合人工复核,才真正有效。
3.5 本章知识体系
下面这张图,是我自己总结的特征工程全流程。你照着这个框架去设计,基本不会漏掉关键环节。
特征工程不是一锤子买卖。它是一个持续迭代的过程。特征构建完,上线跑一段时间,监控发现分布漂移了,回头重新构建,再存储,再监控。这个闭环,才是风控特征工程的核心。
最后说一句:特征工程做得好不好,直接决定风控模型的天花板。我见过太多团队,模型调参调了半年,效果提升不到1%。结果花两周时间重构了几个关键特征,AUC直接涨了5个点。你想想看,哪个投入产出比更高?
公众号:蓝海资料掘金营,微信deep3321