3. 坏账率定义与计算:逐笔坏账、日终坏账、滚动坏账率及高频场景下的特殊处理

在实时风控体系中,坏账率是衡量资产质量与模型效果的核心指标。高频行情场景下,传统T+1或月结坏账率无法满足秒级预警需求。本章将系统定义三种坏账率计算口径,并重点阐述高频场景下的特殊处理逻辑。

3.1 坏账率基础定义

坏账率(Bad Rate)指在特定时间窗口内,被认定为“坏账”的资产占总资产的比例。根据认定时点与计算口径不同,分为以下三种核心类型:

类型 定义 计算窗口 适用场景
逐笔坏账率 单笔订单在生命周期内被标记为坏账的比率 订单生命周期(如30天/90天) 模型训练标签、单笔风险评估
日终坏账率 每日收盘后,当日所有存续订单中已确认为坏账的比例 自然日(T日收盘) 日报、监管报送、日度风控
滚动坏账率 连续滚动窗口内(如近7天/30天)新增坏账金额与同期新增放款金额的比值 滚动时间窗(如7日、30日) 实时监控、趋势预警、模型效果追踪
讲师提示: 在实时风控中,滚动坏账率是最常用的监控口径。它能够平滑单日波动,同时保持对趋势变化的敏感度,适合作为XGBoost哨兵模型的预警目标变量。

3.2 逐笔坏账率计算

逐笔坏账率是微观层面的基础指标,通常用于模型训练标签的生成。其计算逻辑如下:

  1. 定义坏账标准: 逾期超过特定天数(如M3+:逾期90天以上)或触发特定风险事件(如失联、欺诈确认)。
  2. 跟踪订单生命周期: 从放款日开始,持续跟踪至订单结清或达到坏账认定标准。
  3. 计算单笔标签: 若订单在生命周期内被认定为坏账,则标签为1;否则为0。
  4. 汇总统计: 逐笔坏账率 = 坏账订单数 / 总订单数 × 100%。
# 逐笔坏账率计算伪代码
def calculate_loan_bad_rate(loan_df, bad_definition_days=90):
    """
    loan_df: 包含 loan_id, disbursed_date, status, overdue_days
    bad_definition_days: 坏账认定逾期天数阈值
    """
    loan_df['is_bad'] = (loan_df['overdue_days'] >= bad_definition_days) | \
                        (loan_df['status'] == 'bad_debt')
    bad_count = loan_df['is_bad'].sum()
    total_count = len(loan_df)
    bad_rate = bad_count / total_count
    return bad_rate

3.3 日终坏账率计算

日终坏账率是静态截面指标,反映某一时点的资产质量状况。计算步骤如下:

  • 确定统计时点: 通常为每日收盘时间(如16:00)。
  • 筛选存续订单: 所有未结清且未核销的订单。
  • 认定坏账: 截至统计时点,逾期天数超过坏账阈值的订单。
  • 计算比率: 日终坏账率 = 坏账余额 / 总存续余额 × 100%。
注意: 日终坏账率受“分母效应”影响较大。当新增放款量激增时,分母扩大可能导致坏账率被稀释,掩盖真实风险。因此,在高频行情场景下,日终坏账率通常作为辅助参考,而非主要预警指标。

3.4 滚动坏账率计算

滚动坏账率是高频场景下的核心指标,能够有效消除分母效应,反映近期放款质量。其计算公式为:

滚动坏账率 = (滚动窗口内新增坏账金额) / (滚动窗口内新增放款金额) × 100%

具体计算流程:

  1. 设定滚动窗口: 常见窗口为7天、15天、30天。
  2. 计算新增坏账: 在窗口期内,首次达到坏账认定标准的订单的放款金额。
  3. 计算新增放款: 在窗口期内,所有新增放款的金额。
  4. 滚动更新: 每次新数据到达,窗口向前滑动,重新计算。
# 滚动坏账率计算示例(Python)
def rolling_bad_rate(transactions_df, window_days=30):
    """
    transactions_df: 包含 trans_date, loan_amount, is_bad (是否已认定为坏账)
    """
    # 按日期排序
    df = transactions_df.sort_values('trans_date')
    # 计算滚动窗口内的新增放款总额
    df['rolling_disbursed'] = df['loan_amount'].rolling(
        window=window_days, min_periods=1).sum()
    # 计算滚动窗口内的新增坏账总额
    df['rolling_bad'] = df['loan_amount'][df['is_bad'] == 1].rolling(
        window=window_days, min_periods=1).sum()
    # 计算滚动坏账率
    df['rolling_bad_rate'] = df['rolling_bad'] / df['rolling_disbursed']
    return df

3.5 高频场景下的特殊处理

在毫秒级高频行情场景中,传统坏账率计算面临三大挑战:延迟认定、数据稀疏、计算时效。以下是针对性的特殊处理方案:

挑战 问题描述 高频处理方案
延迟认定 坏账认定需要等待逾期天数达到阈值(如90天),导致指标滞后 使用代理标签:如早期逾期率(DPD1+、DPD7+)作为坏账的近似替代,训练XGBoost模型预测最终坏账概率
数据稀疏 高频切片(如每分钟)内坏账事件极少,导致坏账率为0或剧烈波动 采用累积窗口与指数加权移动平均(EWMA),平滑稀疏数据,同时保留趋势信号
计算时效 全量数据重算滚动坏账率耗时较长,无法满足秒级响应 使用增量计算:维护窗口内放款总额与坏账总额的累加器,新数据到达时仅更新边界值,避免全量扫描
实战要点: 在XGBoost哨兵模型中,我们通常使用EWMA平滑后的滚动坏账率作为目标变量。平滑系数α一般设为0.1~0.3,在敏感度与稳定性之间取得平衡。同时,配合代理标签(如7天逾期率)进行模型训练,可提前30~60天发出预警信号。

3.6 高频坏账率计算架构

下图展示了高频行情场景下,坏账率计算的实时数据流与处理架构:

高频坏账率实时计算架构 高频坏账率实时计算架构 行情数据流 交易订单流 实时预处理 • 数据清洗 • 特征工程 • 代理标签计算 增量计算引擎 • 窗口累加器维护 • EWMA平滑 • 滚动坏账率更新 实时坏账率输出 逐笔 / 日终 / 滚动 XGBoost哨兵 实时预警决策 预警信号 风控决策引擎 架构说明: • 数据流经预处理后,进入增量计算引擎,避免全量重算,满足毫秒级响应。 • 滚动坏账率作为XGBoost哨兵模型的核心输入特征,驱动实时预警决策。 • 预警信号直接推送至风控决策引擎,实现自动化处置(如降额、限流、人工审核)。

3.7 三种坏账率对比与选型建议

在实际项目中,应根据监控目标与数据频率选择合适的坏账率口径。下表总结了三种口径的对比:

维度 逐笔坏账率 日终坏账率 滚动坏账率
计算粒度 单笔订单 日频截面 滚动窗口
时效性 低(需等待生命周期结束) 中(T+1) 高(实时更新)
平滑性 不适用 受分母效应影响大 EWMA平滑后稳定
高频适用性 不适合 辅助参考 核心指标
模型训练用途 标签生成 离线评估 实时特征与目标变量
选型建议: 在《高频行情坏账率哨兵》课程项目中,我们采用滚动坏账率(30天窗口,EWMA平滑)作为XGBoost模型的实时监控目标。同时,使用逐笔坏账率生成训练标签,日终坏账率作为日报与监管报送口径。三者协同,构建完整的坏账率监控体系。