4. 标签定义与目标变量:如何定义“好客户”与“坏客户”,连续型额度定价目标变量的处理

在额度定价模型中,标签定义直接决定了模型学习的方向。错误的标签定义会导致模型“学偏”,即使特征工程再完美,也无法产出合理的额度策略。本章将系统讲解分类任务中的“好/坏客户”定义标准,以及回归任务中连续型目标变量的处理方法。

4.1 分类任务:好客户 vs 坏客户

额度定价模型通常首先判断客户的风险等级,因此需要将客户划分为“好”与“坏”两类(或多类)。定义标准必须兼顾业务容忍度与数据分布。

4.1.1 核心定义维度

维度 典型定义 适用场景
逾期天数 逾期 ≥ 30天 为坏客户 消费金融、信用卡
逾期金额 逾期金额 ≥ 本金 20% 为坏客户 大额分期、抵押贷
核销标记 已核销 / 委外催收为坏客户 银行、持牌消金
复合指标 逾期 ≥ 30天 且 金额 ≥ 500元 通用风控模型
实践建议:定义“坏客户”时,建议设置 观察期 + 表现期。例如:观察客户在放款后 6 个月内的表现,逾期 ≥ 30 天即标记为坏。表现期太短(如 1 个月)会导致坏样本不充分;太长(如 12 个月)则样本时效性差。

4.1.2 常见定义陷阱与避坑

  • 样本不平衡陷阱:坏客户占比通常低于 5%,直接建模会导致模型偏向预测“好客户”。需采用下采样、SMOTE 或代价敏感学习。
  • 时间窗口不一致:不同批次客户的观察期长度不同,需统一截断或使用生存分析。
  • 多头借贷干扰:客户可能在多个平台同时逾期,单一平台标签可能失真,建议引入外部征信数据交叉验证。
案例:某消费金融平台最初将“逾期 ≥ 90 天”定义为坏客户,导致坏样本仅占 0.8%,模型 AUC 仅 0.62。后将定义调整为“逾期 ≥ 30 天”,坏样本占比升至 3.5%,AUC 提升至 0.78,额度定价的区分度显著改善。

4.2 连续型目标变量:额度定价的回归任务

当模型直接输出建议额度或利率时,目标变量是连续值。此时需要处理截断、偏态分布和业务约束问题。

4.2.1 目标变量类型与处理策略

目标变量类型 原始分布特点 推荐处理方式
授信额度 右偏、长尾、有上限 对数变换 (log1p) 或 Box-Cox
利率 / 费率 集中在几个档位,离散化 分箱后做有序回归或分类
风险评分 近似正态,但有极端值 Winsorize 截断 + 标准化
损失金额 (LGD) 大量 0 值 + 右偏 两阶段模型:先分类是否损失,再回归损失金额

4.2.2 连续目标变量处理流程

  1. 缺失值处理:额度为 0 或空值需单独标记,不可直接填充。
  2. 异常值截断:使用百分位数(如 1% ~ 99%)或业务上限截断。
  3. 分布变换:优先尝试 log1p 变换,使分布接近正态。
  4. 分箱离散化(可选):当业务需要固定额度档位时,将连续值映射为等级。
  5. 目标编码对齐:确保训练集与测试集使用相同的变换参数。
注意:连续型目标变量在建模后,预测值需要做 逆变换 才能还原为实际额度。例如使用 log1p 变换,预测后需执行 expm1() 还原。逆变换参数必须与训练集一致,否则额度会系统性偏移。

4.3 标签定义与目标变量处理流程总览

下图展示了从原始数据到最终标签/目标变量的完整处理链路:

标签定义与目标变量处理流程 标签定义与目标变量处理流程 原始数据 任务类型判断 分类任务 定义好/坏客户 逾期天数/金额/核销 二分类标签 (0/1) 回归任务 连续目标变量 缺失/异常/偏态处理 变换后连续值 训练集切分

4.4 代码示例:连续目标变量处理

以下代码展示了从原始额度数据到建模目标变量的完整处理过程:

import numpy as np
import pandas as pd
from scipy.stats import boxcox

def process_continuous_target(df, target_col='credit_limit', method='log1p'):
    """
    连续目标变量处理函数
    :param df: 原始DataFrame
    :param target_col: 目标变量列名
    :param method: 变换方法 ('log1p', 'boxcox', 'winsorize')
    :return: 处理后的DataFrame和变换参数
    """
    data = df.copy()
    
    # 1. 缺失值标记
    data[target_col + '_missing'] = data[target_col].isnull().astype(int)
    data[target_col].fillna(0, inplace=True)
    
    # 2. 异常值截断 (Winsorize)
    lower = data[target_col].quantile(0.01)
    upper = data[target_col].quantile(0.99)
    data[target_col] = data[target_col].clip(lower, upper)
    
    # 3. 分布变换
    if method == 'log1p':
        data[target_col + '_trans'] = np.log1p(data[target_col])
        transform_params = {'method': 'log1p'}
    elif method == 'boxcox':
        transformed, lambda_val = boxcox(data[target_col] + 1)  # +1 避免0值
        data[target_col + '_trans'] = transformed
        transform_params = {'method': 'boxcox', 'lambda': lambda_val}
    elif method == 'winsorize':
        # 仅截断,不做变换
        data[target_col + '_trans'] = data[target_col]
        transform_params = {'method': 'winsorize', 'lower': lower, 'upper': upper}
    
    return data, transform_params

# 使用示例
df = pd.DataFrame({'credit_limit': [0, 5000, 10000, 50000, 200000, None]})
df_processed, params = process_continuous_target(df, method='log1p')
print(df_processed[['credit_limit', 'credit_limit_trans']])

4.5 标签定义与目标变量选择决策矩阵

业务场景 推荐标签类型 目标变量 处理要点
新客额度审批 二分类(好/坏) 是否违约 表现期 ≥ 6个月,逾期 ≥ 30天
存量客户提额 回归 建议额度 log1p变换,截断极端值
利率差异化定价 有序分类 利率档位 分箱后做有序逻辑回归
损失准备金计提 两阶段 是否损失 + 损失金额 先分类再回归,处理零膨胀
核心原则:标签定义必须 可回溯、可验证、可解释。每次模型迭代时,标签定义逻辑应作为元数据与模型版本一同保存,避免因定义漂移导致模型效果评估失真。