金融风控场景中的算法实践:决策树与规则引擎的协同设计

金融风控场景中的算法实践:决策树与规则引擎的协同设计

一、为什么金融风控系统从来不用单一模型

电商的推荐系统可以用一个大的深度学习模型来承担绝大部分工作,但金融风控系统不行。一个风控决策流中,通常是多个环节的串联:先过规则引擎(黑名单、单笔限额、频次限制),再过机器学习模型(评分卡、决策树、XGBoost),最后人工审核兜底。这种"规则 + 模型 + 人工"的协同模式不是技术能力不够,而是由金融风控场景的两个特殊需求决定的。

第一是可解释性。一笔交易被拒绝了,必须能回答"为什么拒绝"。规则引擎的答案是确定的——"因为 IP 在黑名单中"。黑盒模型的答案是模糊的——"因为模型的评分超过了阈值"。在很多合规场景中,监管需要明确的拒绝理由,模型给出的是概率,风险团队需要能说清楚"这个概率是怎么来的"。

第二是实时性。规则引擎的判断是毫秒级的(查一次缓存),小型模型的推理也是毫秒级的。但深度模型的推理可能需要几十到几百毫秒。在支付链路中,几百毫秒的延迟是红线。所以风控系统通常会先用规则和轻量模型做"粗筛",只有落到灰名单区域的请求才进深度模型。

二、规则引擎和决策树的互补

规则引擎用于处理"确定性规则"。比如"同一用户在 5 分钟内发起超过 3 次支付→拒绝"、"交易金额超过单笔 5 万→人工审核"。这些规则是由风控策略专家手工编写的,准确率接近 100%。但规则引擎的局限性也很明显:覆盖范围有限——目前积累的规则可能只覆盖了 60% 的场景,剩下 40% 的交易是规则引擎判断不了的。

决策树(以及 GBDT、XGBoost 等树模型集成)用于处理"概率性判断"。模型从历史数据中学习特征与风险之间的关系,给出一个风险评分。覆盖范围广——几乎任何交易都能给出评分,但其判断不像规则引擎那样可溯源。

两者的协同方式是:规则引擎做确定性过滤,模型做概率性补充。模型判断不了的(置信度不够高的)区域,升级到人工审核。三者的覆盖关系:规则覆盖高确定性的两极(明确安全/明确风险),模型覆盖中间地带,人工覆盖模型的低置信区域。

三、决策树模型的特征工程

风控模型的效果,七分靠特征工程,三分靠模型调参。金融风控的常见特征维度:

  • 用户维度:注册时长、历史交易次数、历史被拒次数、账户余额变动模式。
  • 设备维度:设备是否 Root/越狱、最近设备登录过的账号数量、设备地理位置变化。
  • 交易维度:交易金额、交易时间、对方账户类型(个人/商户/转账)。
  • 行为序列维度:用户在交易前的操作序列(进入页面→查看余额→输入金额→确认支付)是否与历史模式一致。
"""
风控模型特征工程的核心逻辑
关键原则:
1. 所有特征必须能在 O(1) 或 O(log n) 时间内获取
   支付链路中不允许跨服务调用的高延迟特征
2. 特征需要做时间窗口聚合
   最近 1 天/7 天/30 天的行为统计,反映不同时间粒度的风险模式
3. 特征之间需要做交叉
   单特征可能信息量不足,交叉后可能反映更强的风险信号
"""
class RiskFeatureEngineering:
    def build_features(self, user_id, transaction) -> dict:
        """构建一次交易的完整特征向量"""
        features = {}
        # 用户基础特征(从缓存获取,低延迟)
        user_profile = self.cache.get_user_profile(user_id)
        features['reg_days'] = self._days_since(user_profile.reg_time)
        features['total_txn_count'] = user_profile.total_txn_count
        features['reject_ratio_7d'] = user_profile.reject_7d / max(
            user_profile.total_7d, 1)
        # 设备特征
        device_info = self.cache.get_device_info(transaction.device_id)
        features['device_is_rooted'] = int(device_info.is_rooted)
        features['device_account_count'] = device_info.linked_accounts
        # 交易特征
        features['amount'] = transaction.amount
        features['hour_of_day'] = transaction.timestamp.hour
        # 金额偏离度:当前金额 / 该用户历史平均金额
        features['amount_deviation'] = (
            transaction.amount / max(user_profile.avg_amount, 1)
        )
        # 行为序列特征
        behavior_seq = self.cache.get_recent_behaviors(user_id, window=300)
        features['steps_before_pay'] = len(behavior_seq)
        # 与历史行为模式的相似度
        features['seq_similarity'] = self._calc_seq_similarity(
            behavior_seq, user_profile.typical_sequence
        )
        # 交叉特征(信号更强的组合特征)
        features['large_amount_at_night'] = int(
            transaction.amount > 10000 and transaction.timestamp.hour < 6
        )
        features['new_device_large_amount'] = int(
            not device_info.is_known and transaction.amount > 5000
        )
        return features

四、模型效果评估的金融特殊性

推荐系统的评估看 AUC、CTR 这类指标就够了,但风控模型的评估更复杂。

误杀率比召回率更敏感:一个正常用户的支付被拒绝(误杀),带来的用户投诉和体验损失远大于放行了一笔有风险的交易。因此在设定决策阈值时,通常会偏保守——宁可多放几笔有风险的进人工审核,也不轻易直接拒绝。

数据分布是不平衡的:正常的交易占 99.5% 以上,风险交易不到 0.5%。在这种极度不平衡的数据上,准确率(Accuracy)没有意义——一个"全部放行"的模型都有 99.5% 的准确率。评估指标应该用 Precision、Recall、F1、AUC(对不平衡数据相对鲁棒)。

线上效果比离线指标更重要:离线评估中 AUC 0.95 的模型,上线后可能因为离线训练数据的偏差(幸存者偏差、时间分布偏差)而表现远不如预期。必须做 AB 测试,对比新老模型在真实流量下的误杀率和漏过率。

五、总结

金融风控的算法实践和互联网推荐系统有本质的不同。推荐系统追求的是"尽可能准确",风控系统追求的是"不能冤枉一个好人,尽量不放过一个坏人"。这个差异决定了架构必须是规则引擎做确定性、决策树做概率性、人工审核做兜底的三层协同。也决定了评估指标不能只看 AUC,更要关注误杀率和可解释性。对任何一个进入风控领域的算法工程师来说,第一课不是学模型,而是理解"风控错了是有后果的"。

© 版权声明

相关文章