损失函数与评估指标
每一种损失都通过 loss.metric() 提供同定义评估指标,通过
loss.business_metric() 提供对应业务指标,通过 metric.to_scorer()
接入 sklearn 交叉验证。HSCredit 模型可直接接受 objective=loss 与
eval_metric=metric 对象。
完整用法、全部损失对应表、框架训练、早停、CV、调参、金额对齐与迁移说明见 损失函数:训练、评估与调参。
from hscredit import LightGBM
from hscredit.core.models.losses import FocalLoss
loss = FocalLoss(alpha=0.75)
model = LightGBM(objective=loss, n_estimators=100, n_jobs=1)
model.fit(X_train, y_train, eval_set=[(X_valid, y_valid)])
value = loss.metric().evaluate(y_valid, model.predict_proba(X_valid))
统一接口
loss.metric() 越小越好;真实业务指标的方向以 metric.direction 为准。
仅 sklearn scorer 对最小化指标自动取负。所有概率均为坏样本概率。
- class hscredit.core.models.BaseLoss(name='custom_loss')[源代码]
基类:
ABC二分类损失基类。
参数
- 参数:
name (str) -- 损失的标识名称。
属性
gradient/hessian对概率求导,标度为样本数 × 平均损失; 树框架适配器统一转换到原始分数。is_additive表示可安全分批计算。参考样例
>>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss(alpha=0.75) >>> metric = loss.metric() >>> value = metric([0, 1], [0.2, 0.8]) >>> scorer = metric.to_scorer()
- is_additive = False
- abstractmethod gradient(y_true, y_pred)[源代码]
返回对坏样本概率的一阶导数,用于实现训练目标。
- 参数:
y_true (ndarray) -- 形状 (n_samples,) 的 0/1 标签。
y_pred (ndarray) -- 同形状的坏样本概率,通常在数值计算前裁剪至 (0, 1)。
- 返回:
同形状有限数组,定义为
d(n_samples * loss) / dp; 逐样本可加损失等于各行损失的导数,不再除以样本数。- 返回类型:
ndarray
此处对概率 p 求导。框架适配器负责 sigmoid 链式求导与样本权重, 自定义子类不应重复转换为原始分数导数。
>>> from hscredit.core.models.losses import FocalLoss >>> gradient = FocalLoss().gradient([0, 1], [0.2, 0.8])
- hessian(y_true, y_pred)[源代码]
返回对概率的二阶导数,或 None 以请求训练曲率近似。
- 参数:
y_true (ndarray) -- 一维 0/1 标签。
y_pred (ndarray) -- 同形状坏样本概率。
- 返回:
d²(n_samples * loss) / dp²的对角项数组,或 None。 原始数学曲率可为负;树框架适配器转换后会采用正对角近似。- 返回类型:
ndarray | None
>>> from hscredit.core.models.losses import FocalLoss >>> curvature = FocalLoss().hessian([0, 1], [0.2, 0.8])
- loss_values(y_true, y_pred)[源代码]
计算逐样本损失贡献,用于加权评估或可安全分批的训练。
- 参数:
y_true -- 一维 0/1 标签。
y_pred -- 同形状坏样本概率。
- 返回:
一维数组,其普通均值应等于
self(y_true, y_pred)。- 抛出:
NotImplementedError -- 损失依赖完整排序或整体样本分布,无法逐行分解。
自定义损失只有在每行计算不依赖其他行时才应设置
is_additive=True。>>> from hscredit.core.models.losses import FocalLoss >>> values = FocalLoss().loss_values([0, 1], [0.2, 0.8])
- metric(name=None, **sample_params)[源代码]
生成与本损失公式一致的评估指标,越小越好。
- 参数:
name -- 可选的中文指标名称,省略时使用内置名称。
sample_params -- 替换指标副本中的逐行参数,例如
AmountWeightedLoss.metric(amounts=valid_amounts)。 仅支持提供set_sample_params的损失,行顺序须与评估数据一致。
- 返回:
独立的
LossMetric参数快照,可离线调用、传入 ModelTuner, 或转换为 sklearn 评分器、框架监控回调。
>>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss(alpha=0.75) >>> metric = loss.metric(name='验证集聚焦损失') >>> metric.direction 'minimize' >>> value = metric([0, 1], [0.2, 0.8])
- to_metric(name=None, **sample_params)[源代码]
metric的同义方法,参数、快照与返回语义完全相同。- 参数:
name -- 可选的中文指标名称。
sample_params -- 评估数据对应的样本金额或金融参数。
- 返回:
LossMetric实例。
>>> from hscredit.core.models.losses import FocalLoss >>> metric = FocalLoss().to_metric()
- business_metric()[源代码]
获取与损失目标对应的实际业务指标。
- 返回:
BaseMetric实例,继承本损失的头部比例、成本等业务参数。 排序目标对应 AUC,分离目标对应 KS,审批目标对应坏账率、通过率 或利润等。没有专用映射时返回本损失的LossMetric, 例如 FocalLoss 与 AmountWeightedLoss。详见business_metric_for_loss。
损失值用于衡量代理优化目标,业务指标用于衡量实际模型表现, 两者可能有不同的最优模型及优化方向,应通过
metric.direction判断。>>> from hscredit.core.models.losses import RankingAUCProxyLoss >>> metric = RankingAUCProxyLoss().business_metric() >>> metric([0, 1], [0.2, 0.8]) 1.0
- evaluate(y_true, y_pred, sample_weight=None, *, raw_score=False, **sample_params)[源代码]
校验输入并计算离线损失,建议作为统一评估入口。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 一维坏样本概率,或类别顺序 [0, 1] 的两列概率。
raw_score=True时改为一维原始分数(logit)。sample_weight -- 可选的一维非负样本权重,须有限、等长且总和大于 0。 只有可逐行分解的损失支持额外权重;不得用金额数组替代样本行对齐。
raw_score -- 是否先将一维原始分数转换为坏样本概率,默认 False。
sample_params -- 当前评估数据的金额或金融参数,语义同
metric。
- 返回:
float,原始损失值,越小越好。
>>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss() >>> value = loss.evaluate([0, 1], [[0.8, 0.2], [0.2, 0.8]]) >>> weighted = loss.evaluate([0, 1], [0.2, 0.8], sample_weight=[1, 2])
- to_scorer()[源代码]
生成 sklearn 评分器,自动对损失取负以符合越大越好的约定。
- 返回:
scorer(estimator, X, y_true, sample_weight=None)可调用对象。 模型须有predict_proba,类别为 0 和 1。- 抛出:
ValueError -- 已绑定逐行金额等数组,无法在 sklearn CV 中自动切分。
>>> from hscredit.core.models.losses import FocalLoss >>> from sklearn.model_selection import cross_val_score >>> scorer = FocalLoss().to_scorer() >>> scores = cross_val_score(model, X, y, scoring=scorer, cv=3)
- to_xgboost(api='native')[源代码]
生成 XGBoost 自定义目标,自动处理原始分数、链接函数和权重。
- 参数:
api --
'native'返回objective(preds, DMatrix),用于xgboost.train(obj=...);'sklearn'返回objective(y_true, y_pred, sample_weight=None),用于 XGBClassifier。- 返回:
返回
(grad, hess)两个等长数组的目标回调。 输入预测始终为原始分数;非凸目标采用正对角 Hessian 近似。- 抛出:
ValueError -- api 无效,或跨样本损失被传入额外权重。
>>> from hscredit.core.models.losses import FocalLoss >>> from xgboost import XGBClassifier >>> loss = FocalLoss(alpha=0.75) >>> model = XGBClassifier(objective=loss.to_xgboost(api='sklearn'))
- to_lightgbm(api='sklearn')[源代码]
生成 LightGBM 自定义目标。
- 参数:
api -- 默认
'sklearn',用于LGBMClassifier(objective=...);'native'用于lightgbm.train的 params['objective']。- 返回:
返回 (grad, hess) 的回调;原始分数、权重与曲率语义同
to_xgboost。
>>> from hscredit.core.models.losses import FocalLoss >>> from lightgbm import LGBMClassifier >>> model = LGBMClassifier(objective=FocalLoss().to_lightgbm())
- to_catboost()[源代码]
生成 CatBoost 自定义目标,自动提供 CatBoost 约定的负导数。
- 返回:
带
calc_ders_range(approxes, targets, weights)的目标对象。 接收原始分数,返回逐行 (-grad, -hess)。- 抛出:
ValueError -- 损失不能安全分批计算,例如全量排序或绑定金额数组。
>>> from hscredit.core.models.losses import FocalLoss >>> from catboost import CatBoostClassifier >>> model = CatBoostClassifier(loss_function=FocalLoss().to_catboost(), eval_metric='AUC')
- to_ngboost()[源代码]
生成 NGBoost Score;必须同时使用返回类的 distribution。
- 返回:
NGBoost Score 子类,
score_class.distribution是配套的 Bernoulli 分布子类;训练接收标签,内部自行读取坏样本概率。- 抛出:
ImportError -- NGBoost 未安装。
ValueError -- 损失不能安全地逐行、分批计算。
推荐
ngboost_params一并配置 Score 和 Dist,避免遗漏。>>> from hscredit.core.models.losses import FocalLoss >>> from ngboost import NGBClassifier >>> score_class = FocalLoss().to_ngboost() >>> model = NGBClassifier(Score=score_class, Dist=score_class.distribution)
- class hscredit.core.models.losses.BaseMetric(name='自定义指标', greater_is_better=True)[源代码]
基类:
ABC可用于离线评估、训练监控及调参的统一指标。
参数
- 参数:
name -- 指标名称。
greater_is_better -- True 表示越大越好。
属性
direction 可直接用于 Optuna 的 maximize / minimize。
参考样例
>>> from hscredit.core.models.losses import FocalLoss >>> metric = FocalLoss().metric() >>> value = metric.evaluate([0, 1], [0.1, 0.9]) >>> scorer = metric.to_scorer()
自定义指标只需实现
__call__(y_true, y_pred, sample_weight=None)并 指定优化方向;不支持权重时可省略该参数,传权重会显式报错。 离线场景优先调用evaluate以获取输入和返回值校验。- property direction
返回
'maximize'或'minimize',可直接传给 Optuna。>>> from hscredit.core.models.losses import FocalLoss >>> FocalLoss().metric().direction 'minimize'
- evaluate(y_true, y_pred, sample_weight=None, *, raw_score=False)[源代码]
离线评估统一入口,校验标签、概率、权重和返回值。
- 参数:
y_true -- 一维、非空 0/1 标签。
y_pred -- 一维坏样本概率,或列顺序 [0, 1] 的两列概率。
raw_score=True时接收一维 logit,并先做 sigmoid。sample_weight -- 可选一维非负有限数组,等长且总和大于 0; 指标子类必须声明支持此参数。
raw_score -- 是否将一维原始分数转为坏样本概率,默认 False。
- 返回:
float,原始指标值,不根据优化方向改变符号。
- 抛出:
ValueError -- 输入无效、权重不支持,或指标返回非有限值。
>>> from hscredit.core.models.losses import AUCMetric >>> AUCMetric().evaluate([0, 1], [[0.8, 0.2], [0.2, 0.8]]) 1.0 >>> AUCMetric().evaluate([0, 1], [-2.0, 2.0], raw_score=True) 1.0
- to_scorer()[源代码]
生成 sklearn CV 或 GridSearchCV 使用的评分器。
- 返回:
独立参数快照,签名为
scorer(estimator, X, y_true, sample_weight=None)。 根据estimator.classes_选择类别 1 的预测概率;仅在此处 对越小越好的指标取负,保持 sklearn 越大越好的约定。
>>> from hscredit.core.models.losses import AUCMetric >>> from sklearn.model_selection import GridSearchCV >>> search = GridSearchCV(model, {'C': [0.1, 1]}, scoring=AUCMetric().to_scorer())
- to_xgboost(api='native', *, raw_score=False)[源代码]
生成 XGBoost 指标回调。
- 参数:
api --
'native'用于xgboost.train(custom_metric=...);'sklearn'用于XGBClassifier(eval_metric=...)。raw_score -- 使用自定义训练目标时设为 True;内置 logistic 目标 通常传来概率,保持 False。转换只做一次,不能同时外部 sigmoid。
- 返回:
native 回调
metric(preds, DMatrix) -> (name, value); sklearn 回调metric(y_true, y_pred, sample_weight=None) -> value。
原生 train 还需 maximize=metric.greater_is_better;sklearn 早停需配置 相同方向的 EarlyStopping 回调。HSCredit 模型可自动完成这些配置。
>>> from hscredit.core.models.losses import FocalLoss >>> callback = FocalLoss().metric().to_xgboost(raw_score=True) >>> sklearn_callback = FocalLoss().metric().to_xgboost(api='sklearn', raw_score=True)
- to_lightgbm(api='sklearn', *, raw_score=False)[源代码]
生成 LightGBM 指标回调,返回值自动携带优化方向。
- 参数:
api --
'sklearn'用于LGBMClassifier.fit(eval_metric=...);'native'用于lightgbm.train(feval=...)。raw_score -- 与自定义目标一起使用时设 True,内置概率目标用 False。
- 返回:
返回
(name, value, greater_is_better)的回调。 native 参数为 (preds, Dataset),sklearn 为 (y_true, y_pred, weight=None)。
>>> from hscredit.core.models.losses import FocalLoss >>> callback = FocalLoss().metric().to_lightgbm(raw_score=True) >>> native_callback = FocalLoss().metric().to_lightgbm(api='native', raw_score=True)
- to_catboost()[源代码]
生成 CatBoost 指标对象,自动将原始分数转换为概率。
- 返回:
提供 evaluate、get_final_error、is_max_optimal 的对象。 evaluate 返回 (指标值 × 权重和, 权重和),最终结果还原为指标值。 标记为不可加,以保留 AUC、KS、排序和逐行金额指标的全量评估语义。
>>> from hscredit.core.models.losses import FocalLoss >>> callback = FocalLoss().metric().to_catboost() >>> callback.is_max_optimal() False
- class hscredit.core.models.losses.LossMetric(loss, name=None, **sample_params)[源代码]
基类:
BaseMetric每一种 BaseLoss 的配套评估指标。
参数
- 参数:
loss -- 损失实例;创建时复制其参数,评估不会改变训练对象。
name -- 自定义指标名,默认采用中文名称。
sample_params -- 替换副本的样本参数,例如
amounts=valid_amounts; 须与验证集逐行对应,支持范围由损失的set_sample_params决定。
属性
loss 保存参数快照;greater_is_better=False。
参考样例
>>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss(alpha=0.75) >>> metric = loss.metric() >>> metric([0, 1], [0.2, 0.8]) == loss.evaluate([0, 1], [0.2, 0.8]) True
- to_scorer()[源代码]
生成 sklearn 评分器,并检查样本参数能否安全用于交叉验证。
- 返回:
scorer(estimator, X, y_true, sample_weight=None),输出负损失。- 抛出:
ValueError -- 指标绑定 amounts、lgd、ead、rate 或 cost 的逐行数组; 应在每折内切分对应数组并重新构造指标,或用 ModelTuner 的折内适配。
>>> from hscredit.core.models.losses import FocalLoss >>> scorer = FocalLoss().metric().to_scorer()
自定义评估函数
只需要新评价口径时,优先用 make_metric 包装普通概率评估函数;
需要状态和额外方法时继承 BaseMetric;训练目标才需要实现 BaseLoss。
- hscredit.core.models.losses.make_metric(function, *, name='自定义指标', greater_is_better, **kwargs)[源代码]
用一行代码定义离线、训练及调参共用的自定义指标。
- 参数:
function --
(y_true, probability, **kwargs) -> float的函数。 输入是坏样本概率,不能传 sklearn scorer 或 XGBoost/LightGBM 回调。name -- 显示名称,默认“自定义指标”。
greater_is_better -- True 表示越大越好,False 表示越小越好;必须显式提供。
kwargs -- 转交函数的固定业务参数,不能包含样本数组权重。
- 返回:
CallableMetric,可直接传
ModelTuner(metric=...)或LightGBM(eval_metric=...);CV 使用返回对象的to_scorer()。
参考样例
>>> from sklearn.metrics import log_loss >>> metric = make_metric(log_loss, name="交叉熵", greater_is_better=False, labels=[0, 1]) >>> metric.direction 'minimize' >>> round(metric([0, 1], [0.1, 0.9]), 3) 0.105
- class hscredit.core.models.losses.CallableMetric(function, *, name='自定义指标', greater_is_better, **kwargs)[源代码]
基类:
BaseMetric包装返回标量的概率评估函数。
参数
- 参数:
function --
function(y_true, probability, **kwargs) -> float。 第一项为0/1标签,第二项为坏样本概率;不接受 sklearn scorer 或框架回调协议。name -- 中文显示名称,默认“自定义指标”。多指标时请使用不同名称。
greater_is_better -- 必须明确指定 True(最大化)或 False(最小化)。
kwargs -- 固定业务参数,例如阈值或收益参数;创建时复制。 样本权重请在评价时通过
sample_weight提供,不可绑定整个数据集。
属性
direction、evaluate、to_scorer和框架适配方法继承自 BaseMetric。参考样例
>>> import numpy as np >>> def error(y, p): ... return float(np.mean((y - p) ** 2)) >>> metric = CallableMetric(error, name="概率均方误差", greater_is_better=False) >>> round(metric([0, 1], [0.1, 0.9]), 2) 0.01
分类与类别不平衡损失
- class hscredit.core.models.FocalLoss(alpha=0.25, gamma=2.0, name='focal_loss')[源代码]
基类:
BaseLossFocal Loss,通过调整样本权重来解决类别不平衡问题。
- 数学公式:
FL(p_t) = -α_t * (1 - p_t)^γ * log(p_t)
- 其中:
p_t = p if y=1 else 1-p α_t = α if y=1 else 1-α
- 参数:
alpha (float) -- 正样本权重,默认为0.25,用于平衡正负样本的总体权重
gamma (float) -- 聚焦参数,默认为2.0,控制易分类样本的权重衰减程度 - gamma=0: 等价于类别加权交叉熵 - gamma越大,易分类样本权重越小
name (str) -- 损失函数名称,默认为"focal_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import FocalLoss >>> >>> # 创建损失函数 >>> loss = FocalLoss(alpha=0.75, gamma=2.0) >>> >>> # 计算损失 >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.4, 0.6, 0.9]) >>> loss_value = loss(y_true, y_pred) >>> >>> # 在XGBoost中使用 >>> import xgboost as xgb >>> dtrain = xgb.DMatrix(X_train, label=y_train) >>> params = {'objective': 'binary:logistic'} >>> bst = xgb.train(params, dtrain, obj=loss.to_xgboost(), num_boost_round=100)
引用
Lin, T.-Y., Goyal, P., Girshick, R., He, K., & Dollár, P. (2017). Focal Loss for Dense Object Detection. ICCV 2017. https://arxiv.org/abs/1708.02002
- gradient(y_true, y_pred)[源代码]
逐样本损失相对坏样本概率的一阶导。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
逐样本损失相对坏样本概率的二阶导。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
逐样本 Focal 损失,其均值等于本损失。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.AsymmetricFocalLoss(alpha=0.25, gamma_pos=2.0, gamma_neg=1.0, clip_value=0.0, name='asymmetric_focal_loss')[源代码]
基类:
BaseLoss不对称 Focal Loss。
与标准 Focal Loss 不同,该损失允许对正负样本使用不同的聚焦参数, 从而更灵活地强调坏样本识别或抑制易分类好样本的影响。
- 数学形式:
正样本: -alpha * (1 - p)^gamma_pos * log(p)
负样本: -(1 - alpha) * p^gamma_neg * log(1 - p)
- 参数:
alpha (float) -- 正样本权重,默认 0.25
gamma_pos (float) -- 正样本聚焦参数,默认 2.0
gamma_neg (float) -- 负样本聚焦参数,默认 1.0
clip_value (float) -- 对负样本概率进行裁剪,抑制极端易分类负样本影响,默认 0.0
name (str) -- 损失函数名称,默认 "asymmetric_focal_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import AsymmetricFocalLoss >>> loss = AsymmetricFocalLoss(alpha=0.7, gamma_pos=2.5, gamma_neg=1.0) >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.4, 0.6, 0.9]) >>> round(loss(y_true, y_pred), 6) >= 0 True
引用
在 Focal Loss(Lin et al., 2017, https://arxiv.org/abs/1708.02002)基础上对正负样本 采用不同聚焦参数,思想与非对称损失 Ben-Baruch, E. et al. (2021). Asymmetric Loss for Multi-Label Classification 相通(https://arxiv.org/abs/2009.14119)。
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import AsymmetricFocalLoss >>> loss = AsymmetricFocalLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import AsymmetricFocalLoss >>> loss = AsymmetricFocalLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
逐样本不对称 Focal 损失;负类截断区内导数为零。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import AsymmetricFocalLoss >>> loss = AsymmetricFocalLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.losses.BalancedFocalLoss(gamma=2.0, beta=0.999, label_smoothing=0.0, auto_alpha=True, alpha=0.25, name='balanced_focal_loss')[源代码]
基类:
BaseLoss平衡 Focal Loss,在 FocalLoss 上加入更稳定的类别平衡方案。
核心改进(相比标准 FocalLoss):
有效样本数加权: 基于 Class-Balanced Loss 论文,用
E_n = (1 - β^n) / (1 - β)自动计算正负样本权重, 比手动设置 alpha 更鲁棒。标签平滑: 将硬标签 {0,1} 软化为 {ε/2, 1-ε/2}, 减少过拟合并提升梯度稳定性。
数学形式:
y_smooth = y × (1-ε) + ε/2 p_t = y_smooth × p + (1-y_smooth) × (1-p) E_pos = (1-β^n_pos) / (1-β) E_neg = (1-β^n_neg) / (1-β) alpha = E_neg / (E_pos+E_neg) w_t = alpha if y=1 else 1-alpha Loss = -w_t × (1-p_t)^γ × log(p_t)
- 参数:
gamma (float) -- 聚焦参数,默认 2.0 - gamma=0 且 label_smoothing=0 时退化为类别加权交叉熵 - gamma 越大,易分类样本权重衰减越快
beta (float) -- 有效样本数衰减因子,默认 0.999 - 内部经验: 0.99~0.9999 之间;样本量越大建议 beta 越接近 1
label_smoothing (float) -- 标签平滑系数,默认 0.0(不启用) - 内部经验: 0.01~0.1 之间可改善校准; 过大会降低区分度
auto_alpha (bool) -- 是否自动根据有效样本数计算 alpha,默认 True - 当 auto_alpha=False 时回退为固定 alpha
alpha (float) -- 固定正样本权重,仅在 auto_alpha=False 时生效,默认 0.25
name (str) -- 损失函数名称,默认 "balanced_focal_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import BalancedFocalLoss >>> >>> # 自动平衡(推荐) >>> loss = BalancedFocalLoss(gamma=2.0, beta=0.999, label_smoothing=0.05) >>> >>> y_true = np.array([0, 0, 0, 0, 1]) # 极不平衡 >>> y_pred = np.array([0.1, 0.2, 0.3, 0.4, 0.8]) >>> loss_value = loss(y_true, y_pred) >>> >>> # 在 XGBoost 中使用 >>> import xgboost as xgb >>> dtrain = xgb.DMatrix(X_train, label=y_train) >>> bst = xgb.train({}, dtrain, obj=loss.to_xgboost(), num_boost_round=100)
引用
有效样本数加权出自 Cui, Y., Jia, M., Lin, T.-Y., Song, Y., & Belongie, S. (2019). Class-Balanced Loss Based on Effective Number of Samples. CVPR 2019. https://arxiv.org/abs/1901.05555 ;聚焦项来自 Focal Loss(Lin et al., 2017, https://arxiv.org/abs/1708.02002)。
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import BalancedFocalLoss >>> loss = BalancedFocalLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import BalancedFocalLoss >>> loss = BalancedFocalLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
逐样本贡献;auto_alpha=True 时权重依赖整个评估数据集。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import BalancedFocalLoss >>> loss = BalancedFocalLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.WeightedBCELoss(pos_weight=1.0, neg_weight=1.0, auto_balance=False, name='weighted_bce')[源代码]
基类:
BaseLoss加权二元交叉熵损失,通过为正负样本分配不同权重来处理类别不平衡问题。
数学公式: Loss = -[w_pos * y * log(p) + w_neg * (1-y) * log(1-p)]
- 参数:
pos_weight (float) -- 正样本权重,默认为1.0
neg_weight (float) -- 负样本权重,默认为1.0
auto_balance (bool) -- 是否自动根据样本比例平衡权重,默认为False。如果为True,pos_weight和neg_weight将被忽略
name (str) -- 损失函数名称,默认为"weighted_bce"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import WeightedBCELoss >>> >>> # 手动设置权重 >>> loss = WeightedBCELoss(pos_weight=5.0, neg_weight=1.0) >>> >>> # 自动平衡权重 >>> loss = WeightedBCELoss(auto_balance=True) >>> # 假设正样本占比10%,自动设置pos_weight=9, neg_weight=1 >>> >>> # 同一目标的离线评估:越小越好 >>> value = loss.metric()(y_valid, p_valid) >>> # 在LightGBM 4.x 原生接口中使用 >>> import lightgbm as lgb >>> train_data = lgb.Dataset(X_train, label=y_train) >>> bst = lgb.train( ... params={'objective': loss.to_lightgbm(api='native'), 'metric': 'None'}, ... train_set=train_data, ... feval=loss.metric().to_lightgbm(api='native', raw_score=True), ... num_boost_round=100 ... )
引用
类别加权(class weighting)是处理不平衡数据的经典成本敏感方法,参见 King, G., & Zeng, L. (2001). Logistic Regression in Rare Events Data. Political Analysis 9(2), 以及 Elkan, C. (2001). The Foundations of Cost-Sensitive Learning. IJCAI 2001。
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import WeightedBCELoss >>> loss = WeightedBCELoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import WeightedBCELoss >>> loss = WeightedBCELoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
逐样本类别加权 BCE;自动权重按当前数据集重新计算。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import WeightedBCELoss >>> loss = WeightedBCELoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.CostSensitiveLoss(fn_cost=1.0, fp_cost=1.0, name='cost_sensitive')[源代码]
基类:
BaseLoss成本敏感损失函数,根据不同预测错误的成本为不同类型的错误分配不同的权重。
特别适合金融风控场景,因为漏抓坏客户的成本往往远大于误拒好客户的成本。
- 参数:
fn_cost (float) -- 假阴性成本(漏抓坏客户的成本),默认为1.0
fp_cost (float) -- 假阳性成本(误拒好客户的成本),默认为1.0
name (str) -- 损失函数名称,默认为"cost_sensitive"
参考样例
>>> from hscredit.core.models.losses import CostSensitiveLoss >>> >>> # 假设漏抓一个坏客户损失10000元,误拒一个好客户损失100元 >>> # 成本比例为100:1 >>> loss = CostSensitiveLoss(fn_cost=100, fp_cost=1) >>> >>> # 在模型中使用 >>> import xgboost as xgb >>> dtrain = xgb.DMatrix(X_train, label=y_train) >>> params = {'objective': 'binary:logistic'} >>> bst = xgb.train(params, dtrain, obj=loss.to_xgboost(), num_boost_round=100)
注意
损失矩阵:
预测负 预测正 实际负 0 fp_cost 实际正 fn_cost 0
我们希望最小化总成本: FP * fp_cost + FN * fn_cost
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import CostSensitiveLoss >>> loss = CostSensitiveLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import CostSensitiveLoss >>> loss = CostSensitiveLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- classification_cost(y_true, y_pred, threshold=0.5)[源代码]
计算固定阈值下的实际人均误判成本,越小越好。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状的坏样本概率。
threshold -- 拒绝阈值,范围 [0, 1],默认 0.5;p >= threshold 拒绝。
- 返回:
float,误拒好客户成本和漏抓坏客户成本之和除以全量人数。 这是硬决策评价,不作为可微训练目标。
- 返回类型:
float
>>> cost = CostSensitiveLoss(fn_cost=100, fp_cost=1).classification_cost( ... [0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9], threshold=0.5)
- loss_values(y_true, y_pred)[源代码]
成本加权 BCE 的逐样本贡献,其均值与默认调用一致。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import CostSensitiveLoss >>> loss = CostSensitiveLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
审批、利润与金额损失
- class hscredit.core.models.BadDebtLoss(target_approval_rate=0.3, bad_debt_weight=1.0, approval_weight=0.5, name='bad_debt_loss')[源代码]
基类:
BaseLoss坏账率优化损失函数,最小化坏账率同时保持通过率在合理水平。
适用于信贷审批场景,希望降低通过客户的坏账比例。
业务惩罚依赖硬阈值,训练仅使用 BCE 代理导数;本类不直接对坏账率求导。
- 参数:
target_approval_rate (float) -- 目标通过率,范围 (0, 1],默认为0.3
bad_debt_weight (float) -- 坏账率权重,默认为1.0
approval_weight (float) -- 通过率权重,默认为0.5
name (str) -- 损失函数名称,默认为"bad_debt_loss"
参考样例
>>> from hscredit.core.models.losses import BadDebtLoss >>> >>> # 目标通过率30%,重点优化坏账率 >>> loss = BadDebtLoss( ... target_approval_rate=0.3, ... bad_debt_weight=1.0, ... approval_weight=0.3 ... ) >>> >>> # 该目标依赖全量排序,使用 LightGBM 的全量目标回调 >>> from lightgbm import LGBMClassifier >>> model = LGBMClassifier( ... n_estimators=1000, ... objective=loss.to_lightgbm(), ... metric='None', ... ) >>> model.fit( ... X_train, y_train, eval_set=[(X_valid, y_valid)], ... eval_metric=loss.metric().to_lightgbm(raw_score=True), ... )
引用
在目标通过率约束下最小化坏账率,属信贷审批的业务驱动目标;成本敏感学习背景见 Elkan, C. (2001). The Foundations of Cost-Sensitive Learning. IJCAI 2001。
- gradient(y_true, y_pred)[源代码]
硬审批惩罚无连续导数,训练仅使用 BCE 代理梯度。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import BadDebtLoss >>> loss = BadDebtLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回 BCE 代理目标的概率二阶导。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import BadDebtLoss >>> loss = BadDebtLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.ApprovalRateLoss(target_bad_debt_rate=0.05, name='approval_rate_loss')[源代码]
基类:
BaseLoss通过率优化损失函数,在保证坏账率不超过目标的前提下最大化通过率。
硬阈值通过率用于评估与模型选择;训练仅使用 BCE 代理导数。
- 参数:
target_bad_debt_rate (float) -- 目标坏账率,默认为0.05
name (str) -- 损失函数名称,默认为"approval_rate_loss"
参考样例
>>> from hscredit.core.models.losses import ApprovalRateLoss >>> >>> # 目标坏账率不超过5% >>> loss = ApprovalRateLoss(target_bad_debt_rate=0.05)
- gradient(y_true, y_pred)[源代码]
硬阈值业务项用于评估,训练使用 BCE 代理梯度。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import ApprovalRateLoss >>> loss = ApprovalRateLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import ApprovalRateLoss >>> loss = ApprovalRateLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- approval_rate(y_true, y_pred)[源代码]
在当前数据标签上回看、满足目标坏账率的最大阈值通过率。
用于离线评价,不应据此在测试集选择上线阈值;同分客户统一处理。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状的坏样本概率,低概率优先通过。
- 返回:
float,范围 [0, 1];没有满足约束的客户组时为 0。
- 返回类型:
float
>>> value = ApprovalRateLoss(target_bad_debt_rate=0.05).approval_rate( ... [0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.ProfitMaxLoss(interest_income=1.0, bad_debt_loss=10.0, name='profit_max_loss')[源代码]
基类:
BaseLoss利润最大化损失函数,综合考虑坏账损失和利息收益最大化总利润。
训练目标为成本加权 BCE 代理;
profit()单独计算实际阈值利润。 需要连续软利润目标时使用ExpectedProfitLoss。- 参数:
interest_income (float) -- 单位利息收益,默认为1.0
bad_debt_loss (float) -- 单位坏账损失,默认为10.0
name (str) -- 损失函数名称,默认为"profit_max_loss"
参考样例
>>> from hscredit.core.models.losses import ProfitMaxLoss >>> >>> # 假设每笔贷款利息收益100元,坏账损失1000元 >>> loss = ProfitMaxLoss(interest_income=100, bad_debt_loss=1000)
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import ProfitMaxLoss >>> loss = ProfitMaxLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import ProfitMaxLoss >>> loss = ProfitMaxLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
逐样本利润成本加权 BCE,不等于实际货币利润。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import ProfitMaxLoss >>> loss = ProfitMaxLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- profit(y_true, y_pred, threshold=0.5)[源代码]
计算审批决策后的全体申请客户人均实际利润,越大越好。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状的坏样本概率。
threshold -- 通过阈值,范围 [0, 1],默认 0.5;p < threshold 才通过。
- 返回:
float,通过好客户计收益,通过坏客户计损失,拒绝计零; 分母是全量人数,不是通过人数。
- 返回类型:
float
>>> value = ProfitMaxLoss(interest_income=100, bad_debt_loss=1000).profit( ... [0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.losses.ExpectedProfitLoss(revenue=1.0, default_cost=10.0, cutoff=0.5, temperature=0.1, bce_weight=0.1, name='expected_profit_loss')[源代码]
基类:
BaseLoss期望利润损失函数,将收益、坏账损失和通过决策融合为连续可微的期望利润优化目标。
本损失通过 sigmoid 软通过门构造可微的利润代理。
ProfitMaxLoss则使用收益和坏账成本加权 BCE,两者目标不同。数学形式:
approve_i = σ((cutoff - p_i) / temperature) profit_i = (1 - y_i) × revenue - y_i × default_cost E[profit] = mean(approve_i × profit_i) Loss = -E[profit] + bce_weight × BCE(y, p)
- 参数:
revenue (float) -- 好客户通过后的单位收益,默认 1.0 - 内部经验: 可设为平均利息收入或客均贡献
default_cost (float) -- 坏客户通过后的单位损失,默认 10.0 - 内部经验: 通常为 revenue 的 5~20 倍,视业务坏账回收率而定
cutoff (float) -- 软通过阈值,预测概率低于此值的样本倾向通过,默认 0.5
temperature (float) -- sigmoid 平滑温度,越小通过决策越接近硬阈值,默认 0.1 - 内部经验: 0.05~0.2 之间效果较好;太小梯度集中在阈值附近,太大退化为线性
bce_weight (float) -- 基础交叉熵正则权重,防止利润梯度消失,默认 0.1
name (str) -- 损失函数名称,默认 "expected_profit_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import ExpectedProfitLoss >>> >>> # 每笔贷款利息收益 100 元,坏账损失 1000 元 >>> loss = ExpectedProfitLoss( ... revenue=100, ... default_cost=1000, ... cutoff=0.5, ... temperature=0.1 ... ) >>> >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.3, 0.7, 0.9]) >>> loss_value = loss(y_true, y_pred) >>> >>> # 在 XGBoost 中使用 >>> import xgboost as xgb >>> dtrain = xgb.DMatrix(X_train, label=y_train) >>> bst = xgb.train({}, dtrain, obj=loss.to_xgboost(), num_boost_round=100)
引用
成本敏感学习与基于期望收益/损失的最优决策阈值见 Elkan, C. (2001). The Foundations of Cost-Sensitive Learning. IJCAI 2001. https://cseweb.ucsd.edu/~elkan/rescale.pdf 。本损失以 sigmoid 软通过门将利润目标 转为可微形式,属业务驱动设计。
- gradient(y_true, y_pred)[源代码]
相对概率求导:利润项 + bce_weight × (p-y)/(p(1-p))。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import ExpectedProfitLoss >>> loss = ExpectedProfitLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回真实概率二阶导;非凸区域可以为负,由训练适配器稳定化。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import ExpectedProfitLoss >>> loss = ExpectedProfitLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
负软通过利润与 BCE 正则的逐样本损失。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import ExpectedProfitLoss >>> loss = ExpectedProfitLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.losses.AmountWeightedLoss(amounts=None, normalize=True, floor_weight=0.1, name='amount_weighted_loss')[源代码]
基类:
BaseLoss按授信金额/风险敞口加权的损失函数。
在信贷场景中,不同客户的授信金额差异很大。一个 10 万元客户的 坏账和一个 1000 元客户的坏账,业务影响完全不同。本损失通过 金额加权使模型更关注高金额客户的预测准确性。
数学形式:
w_i = amount_i / mean(amount) # 归一化权重 Loss = weighted_mean(BCE_i, w_i)
- 参数:
amounts (Optional[np.ndarray]) -- 样本级金额/敞口数组, shape (n_samples,)。 可在构造时传入,也可通过
set_sample_params()动态设置。normalize (bool) -- 是否对金额进行均值归一化,默认 True - 归一化后平均权重为 1.0,不影响学习率
floor_weight (float) -- 权重下限,防止低金额样本完全被忽略,默认 0.1
name (str) -- 损失函数名称,默认 "amount_weighted_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import AmountWeightedLoss >>> >>> amounts = np.array([50000, 100000, 200000, 10000]) >>> loss = AmountWeightedLoss(amounts=amounts) >>> >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.3, 0.7, 0.9]) >>> loss_value = loss(y_true, y_pred) >>> >>> # 动态设置金额(适用于每轮训练数据不同的场景) >>> loss2 = AmountWeightedLoss() >>> loss2.set_sample_params(amounts=np.array([30000, 80000, 150000, 5000]))
引用
按风险敞口/金额加权,等价于以"预期损失金额"为代价的样本级成本敏感学习,理论框架见 Elkan, C. (2001). The Foundations of Cost-Sensitive Learning. IJCAI 2001。属信贷 业务驱动设计。
- set_sample_params(amounts)[源代码]
设置样本级金额参数。
- 参数:
amounts (ndarray) -- 金额数组, shape (n_samples,) 必须非负且有限,顺序与当前输入样本一致。
- 返回:
self,原地更新;评估验证集时优先用
loss.metric(amounts=...)创建副本,避免覆盖训练金额。- 返回类型:
>>> loss = AmountWeightedLoss().set_sample_params(amounts=[1000, 2000]) >>> metric = loss.metric(amounts=[3000, 4000])
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import AmountWeightedLoss >>> loss = AmountWeightedLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import AmountWeightedLoss >>> loss = AmountWeightedLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
逐样本贡献已按整体平均权重归一化;其均值等于加权平均 BCE。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import AmountWeightedLoss >>> loss = AmountWeightedLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.losses.ExpectedValueLoss(lgd=0.5, ead=None, rate=0.08, cost=0.0, floor_weight=0.1, name='expected_value_loss')[源代码]
基类:
BaseLoss期望价值损失函数,结合 LGD / EAD / 利率 / 成本进行期望价值优化。
在信贷全生命周期管理中,不同客户的风险敞口(EAD)、违约损失率(LGD)、 收益率各不相同。本损失以这些金融参数构造成本加权 BCE 代理, 返回值不是实际货币利润;metric() 与 business_metric() 均按同一期望价值加权损失评估。
样本级权重:
坏样本 (y=1): 权重 = LGD_i × EAD_i → 漏捕的经济损失 好样本 (y=0): 权重 = rate_i × EAD_i - cost_i → 误拒的机会成本
数学形式:
w_i = y_i × LGD_i × EAD_i + (1-y_i) × max(rate_i × EAD_i - cost_i, ε) Loss = weighted_mean(BCE_i, w_i)
- 参数:
lgd (Union[float, np.ndarray]) -- 违约损失率,标量或数组,默认 0.5 - 标量: 所有样本使用相同 LGD - 数组: 每个样本独立的 LGD, shape (n_samples,)
ead (Optional[Union[float, np.ndarray]]) -- 违约风险敞口,标量或数组,默认 None(使用全 1) - 通常等于授信余额或授信额度
rate (Union[float, np.ndarray]) -- 年化收益率,标量或数组,默认 0.08(8%)
cost (Union[float, np.ndarray]) -- 单客运营成本,标量或数组,默认 0.0
floor_weight (float) -- 权重下限,默认 0.1
name (str) -- 损失函数名称,默认 "expected_value_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import ExpectedValueLoss >>> >>> # 全局参数 >>> loss = ExpectedValueLoss(lgd=0.5, rate=0.12) >>> >>> # 样本级参数 >>> loss = ExpectedValueLoss( ... lgd=np.array([0.4, 0.6, 0.5, 0.3]), ... ead=np.array([50000, 100000, 200000, 30000]), ... rate=0.10, ... cost=500 ... ) >>> >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.3, 0.7, 0.9]) >>> loss_value = loss(y_true, y_pred) >>> >>> # 在 XGBoost 中使用 >>> import xgboost as xgb >>> dtrain = xgb.DMatrix(X_train, label=y_train) >>> bst = xgb.train({}, dtrain, obj=loss.to_xgboost(), num_boost_round=100)
- set_sample_params(lgd=None, ead=None, rate=None, cost=None)[源代码]
设置样本级金融参数。
- 参数:
lgd (float | ndarray | None) -- 违约损失率,标量或一维数组,范围 [0, 1];None 保持原值。
ead (float | ndarray | None) -- 违约风险敞口,非负标量或一维数组;None 保持原值。
rate (float | ndarray | None) -- 年化收益率,非负标量或一维数组;None 保持原值。
cost (float | ndarray | None) -- 单客运营成本,非负标量或一维数组;None 保持原值。
- 返回:
self,原地更新;数组须有限且与之后计算的样本顺序一致。
- 返回类型:
>>> loss = ExpectedValueLoss().set_sample_params(lgd=0.5, ead=[1000, 2000]) >>> metric = loss.metric(ead=[3000, 4000])
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import ExpectedValueLoss >>> loss = ExpectedValueLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import ExpectedValueLoss >>> loss = ExpectedValueLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- loss_values(y_true, y_pred)[源代码]
逐样本贡献已按整体平均权重归一化;其均值等于加权平均 BCE。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的数组,其均值等于本损失值;详见 BaseLoss.loss_values。
参考样例
>>> from hscredit.core.models.losses import ExpectedValueLoss >>> loss = ExpectedValueLoss() >>> result = loss.loss_values([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
排序与头部效果损失
- class hscredit.core.models.OrdinalRankLoss(rank_weight=1.0, bce_weight=1.0, temperature=1.0, max_pairs=20000, random_state=42, name='ordinal_rank_loss')[源代码]
基类:
BaseLoss序数排序损失,兼顾概率拟合与好坏样本排序一致性。
该损失在标准二元交叉熵基础上增加成对排序惩罚项, 鼓励坏样本(label=1)的预测风险高于好样本(label=0)。 导数按 n × 平均损失计算,返回 Hessian 的对角项;框架不使用跨样本二阶项。
- 参数:
rank_weight (float) -- 排序惩罚项权重,默认 1.0
bce_weight (float) -- 交叉熵权重,默认 1.0
temperature (float) -- 排序平滑温度,越小越强调排序间隔,默认 1.0
max_pairs (int) -- 为控制计算开销,最多采样的正负样本对数,默认 20000
random_state (int) -- 随机种子,保证采样对可复现,默认 42
name (str) -- 损失函数名称,默认 "ordinal_rank_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import OrdinalRankLoss >>> loss = OrdinalRankLoss(rank_weight=2.0, bce_weight=1.0) >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.3, 0.7, 0.9]) >>> round(loss(y_true, y_pred), 6) >= 0 True
引用
成对排序(pairwise ranking)优化与 AUC 的等价性见 Burges, C. et al. (2005). Learning to Rank using Gradient Descent (RankNet). ICML 2005, https://www.microsoft.com/en-us/research/publication/learning-to-rank-using-gradient-descent/ ; AUC 与 Wilcoxon–Mann–Whitney 统计量的关系见 Hanley & McNeil (1982)。
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true (ndarray) -- 一维 0/1 标签,1 为坏样本。
y_pred (ndarray) -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
- 返回类型:
ndarray
参考样例
>>> from hscredit.core.models.losses import OrdinalRankLoss >>> loss = OrdinalRankLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true (ndarray) -- 一维 0/1 标签,1 为坏样本。
y_pred (ndarray) -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
- 返回类型:
ndarray
参考样例
>>> from hscredit.core.models.losses import OrdinalRankLoss >>> loss = OrdinalRankLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.LiftFocusedLoss(top_ratio=0.1, penalty_factor=3.0, positive_class_boost=1.5, base_weight=1.0, name='lift_focused_loss')[源代码]
基类:
BaseLoss头部 LIFT 导向损失,对高风险区间样本错误施加更大惩罚。
该损失基于加权二元交叉熵,按照预测风险从高到低分配更大的样本权重, 并在头部区间进一步放大坏样本的惩罚,提升模型在高风险头部样本上的区分能力。 排名权重在每次求导时固定,样本排名切换或同分边界处不可微。
- 参数:
top_ratio (float) -- 头部样本占比,默认 0.10
penalty_factor (float) -- 头部惩罚倍数,默认 3.0
positive_class_boost (float) -- 头部坏样本额外增益倍数,默认 1.5
base_weight (float) -- 非头部样本基础权重,默认 1.0
name (str) -- 损失函数名称,默认 "lift_focused_loss"
示例
>>> import numpy as np >>> from hscredit.core.models.losses import LiftFocusedLoss >>> loss = LiftFocusedLoss(top_ratio=0.2, penalty_factor=4.0) >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.4, 0.7, 0.9]) >>> round(loss(y_true, y_pred), 6) >= 0 True
- gradient(y_true, y_pred)[源代码]
返回损失相对坏样本概率的一阶导数。
- 参数:
y_true (ndarray) -- 一维 0/1 标签,1 为坏样本。
y_pred (ndarray) -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
- 返回类型:
ndarray
参考样例
>>> from hscredit.core.models.losses import LiftFocusedLoss >>> loss = LiftFocusedLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回损失相对坏样本概率的二阶导数。
- 参数:
y_true (ndarray) -- 一维 0/1 标签,1 为坏样本。
y_pred (ndarray) -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
- 返回类型:
ndarray
参考样例
>>> from hscredit.core.models.losses import LiftFocusedLoss >>> loss = LiftFocusedLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.losses.RankingAUCProxyLoss(rank_weight=1.0, bce_weight=1.0, margin=0.2, max_pairs=20000, hard_mining_ratio=1.0, random_state=42, name='ranking_auc_proxy_loss')[源代码]
基类:
BaseLoss排序 AUC 代理损失,使用平方铰链代理优化 AUC / 排序质量。
作为
OrdinalRankLoss的增强版本,核心改进:平方铰链代理:
max(0, margin - Δ)²比 logistic 代理log(1+exp(-Δ))使用不同的间隔惩罚;效果需在验证集比较。硬负例挖掘: 优先选择违反 margin 的样本对(
p_pos - p_neg < margin), 避免在已充分排序的 pair 上浪费梯度。固定 margin: 通过参数控制目标间距;未实现训练进度调度。
硬挖掘选中样本对改变、同分或 hinge 边界处不可微;其余区间按 n × 平均损失 计算概率导数和 Hessian 对角项,不返回跨样本二阶项。
数学形式:
Δ_ij = p_i - p_j (i ∈ pos, j ∈ neg) L_pair = mean(max(0, margin - Δ_ij)²) Loss = bce_weight × BCE + rank_weight × L_pair
- 参数:
rank_weight (float) -- 排序损失权重,默认 1.0
bce_weight (float) -- 交叉熵权重,默认 1.0
margin (float) -- 正负样本预测间距目标,默认 0.2 - 内部经验: 0.1~0.3 之间;margin 过大可能导致梯度爆炸
max_pairs (int) -- 最多采样的正负样本对数,默认 20000
hard_mining_ratio (float) -- 硬负例挖掘比例,默认 1.0(全部使用) - 设为 0.5 则只保留 50% 违反 margin 最严重的 pair
random_state (int) -- 随机种子,保证采样可复现,默认 42
name (str) -- 损失函数名称,默认 "ranking_auc_proxy_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import RankingAUCProxyLoss >>> >>> loss = RankingAUCProxyLoss(rank_weight=2.0, margin=0.2) >>> y_true = np.array([0, 0, 1, 1]) >>> y_pred = np.array([0.1, 0.3, 0.7, 0.9]) >>> round(loss(y_true, y_pred), 6) >= 0 True >>> >>> # 在 XGBoost 中使用 >>> import xgboost as xgb >>> dtrain = xgb.DMatrix(X_train, label=y_train) >>> bst = xgb.train({}, dtrain, obj=loss.to_xgboost(), num_boost_round=200)
引用
平方铰链(squared hinge)排序代理与 AUC 优化见 Joachims, T. (2005). A Support Vector Method for Multivariate Performance Measures. ICML 2005;硬负例挖掘思想见 Shrivastava, A. et al. (2016). Training Region-based Object Detectors with Online Hard Example Mining (OHEM). CVPR 2016. https://arxiv.org/abs/1604.03540
- class hscredit.core.models.losses.KSFocusedLoss(ks_weight=1.0, bce_weight=1.0, var_weight=0.1, focus_weight=2.0, bandwidth=0.1, name='ks_focused_loss')[源代码]
基类:
BaseLossKS 导向损失函数,强化好坏样本预测分布的分离能力。
KS(Kolmogorov-Smirnov)统计量衡量正负样本累积分布的最大距离, 是信贷风控模型评估的核心指标之一。本损失在标准交叉熵基础上增加 分布分离惩罚项,通过以下机制逼近 KS 优化:
均值分离: 最大化 mean(p|y=1) - mean(p|y=0)
分布聚集: 减小类内预测方差,使分布更集中
重叠区聚焦: 在正负分布重叠区域施加更大权重
数学形式:
overlap_i = exp(-(p_i-midpoint)^2 / (2*bandwidth^2)) L = bce_weight × mean((1 + focus_weight × overlap_i) × BCE_i) - ks_weight × [μ₁ - μ₀] + var_weight × [σ₁² + σ₀²] midpoint = (μ₁ + μ₀) / 2;导数包含该均值对所有概率的依赖。 导数按 n × 平均损失计算;训练框架仅使用 Hessian 的对角项。
- 参数:
ks_weight (float) -- 分布分离项权重,默认 1.0 - 内部经验: 0.5~2.0 之间,越大分布分离越强但可能牺牲概率校准
bce_weight (float) -- 基础交叉熵权重,默认 1.0
var_weight (float) -- 类内方差惩罚权重,默认 0.1 - 内部经验: 适度值(0.05~0.3)可减少类内离散度,提升 KS
focus_weight (float) -- 重叠区聚焦倍数,默认 2.0 - 对预测值处于正负分布重叠区的样本额外加权
bandwidth (float) -- 重叠区高斯核带宽,默认 0.1
name (str) -- 损失函数名称,默认 "ks_focused_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import KSFocusedLoss >>> >>> loss = KSFocusedLoss(ks_weight=1.5, var_weight=0.2) >>> y_true = np.array([0, 0, 0, 1, 1, 1]) >>> y_pred = np.array([0.2, 0.3, 0.4, 0.6, 0.7, 0.8]) >>> loss_value = loss(y_true, y_pred) >>> >>> # 在 LightGBM 中使用 >>> import lightgbm as lgb >>> train_data = lgb.Dataset(X_train, label=y_train) >>> bst = lgb.train( ... {'objective': loss.to_lightgbm(api='native'), 'metric': 'None'}, ... train_data, ... feval=loss.metric().to_lightgbm(api='native', raw_score=True), ... num_boost_round=200 ... )
引用
KS(Kolmogorov–Smirnov)统计量见 https://en.wikipedia.org/wiki/Kolmogorov–Smirnov_test ; 其在信用风险中作为核心区分度指标见 Siddiqi, N. (2006). Credit Risk Scorecards. Wiley。 本损失为面向 KS 的可微代理(分布分离 + 重叠区聚焦),属业务驱动设计。
- gradient(y_true, y_pred)[源代码]
包含数据依赖 midpoint 的完整链式导数。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import KSFocusedLoss >>> loss = KSFocusedLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
返回真实概率 Hessian 对角项,非凸区可为负;不包含跨样本项。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import KSFocusedLoss >>> loss = KSFocusedLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- class hscredit.core.models.losses.TopKBadCaptureLoss(top_ratio=0.05, miss_penalty=5.0, fa_penalty=1.0, temperature=0.05, bce_weight=0.1, name='topk_bad_capture_loss')[源代码]
基类:
BaseLossTop-K 坏样本捕获损失,优化头部 k% 的坏样本召回率。
在策略、催收、反欺诈名单筛选场景中,核心目标是在有限资源 (如 top 5% 的高风险名单)下尽可能多地覆盖坏样本。本损失 直接面向该业务目标构造代理。分位数使用线性插值,其依赖纳入导数; 排序切换和同分边界处不可微。Hessian 只返回对角项,框架忽略跨样本项。
核心机制:
计算预测分布的 top-k 分位阈值
通过 sigmoid 软门控判断每个样本是否 "进入" 头部
对未进入头部的坏样本(漏捕)施加重惩罚
对进入头部的好样本(误报)施加轻惩罚
数学形式:
τ_k = percentile(p, 100 - k) gate_i = σ((p_i - τ_k) / temperature) miss_cost = (1 - gate_i) × y_i × miss_penalty fa_cost = gate_i × (1-y_i) × fa_penalty Loss = mean(miss_cost + fa_cost) + bce_weight × BCE
- 参数:
top_ratio (float) -- 头部样本占比,默认 0.05(top 5%) - 内部经验: 策略名单通常 3%~10%;催收通常 5%~20%
miss_penalty (float) -- 漏捕坏样本惩罚倍数,默认 5.0
fa_penalty (float) -- 误报好样本惩罚倍数,默认 1.0
temperature (float) -- sigmoid 平滑温度,默认 0.05 - 内部经验: 0.02~0.1 之间;太小梯度消失,太大 gate 退化
bce_weight (float) -- 基础交叉熵正则权重,默认 0.1
name (str) -- 损失函数名称,默认 "topk_bad_capture_loss"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import TopKBadCaptureLoss >>> >>> # top 5% 名单,重点惩罚漏捕 >>> loss = TopKBadCaptureLoss(top_ratio=0.05, miss_penalty=10.0) >>> >>> y_true = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0, 0]) >>> y_pred = np.array([0.1, 0.2, 0.3, 0.5, 0.8, 0.9, 0.05, 0.15, 0.25, 0.4]) >>> loss_value = loss(y_true, y_pred) >>> >>> # 在 LightGBM 中使用 >>> import lightgbm as lgb >>> train_data = lgb.Dataset(X_train, label=y_train) >>> bst = lgb.train( ... {'objective': loss.to_lightgbm(api='native'), 'metric': 'None'}, ... train_data, ... feval=loss.metric().to_lightgbm(api='native', raw_score=True), ... num_boost_round=200 ... )
引用
面向头部召回(Recall@top-k / Precision@k)的优化目标,对应策略名单/催收/反欺诈的 资源受限决策场景,属业务驱动设计;与排序度量优化相关,参见 Joachims, T. (2005). A Support Vector Method for Multivariate Performance Measures. ICML 2005。
- gradient(y_true, y_pred)[源代码]
分段光滑区间的完整概率导数,包含分位阈值的依赖。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的一阶导数组,标度为样本数乘以平均损失;详见 BaseLoss.gradient。
参考样例
>>> from hscredit.core.models.losses import TopKBadCaptureLoss >>> loss = TopKBadCaptureLoss() >>> result = loss.gradient([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
- hessian(y_true, y_pred)[源代码]
分段光滑区间的 Hessian 对角项,不包含跨样本项。
- 参数:
y_true -- 一维 0/1 标签,1 为坏样本。
y_pred -- 同形状坏样本概率,范围 [0, 1];不是原始分数。
- 返回:
与输入等长的二阶导数组,标度同 BaseLoss.hessian;框架适配器再做链接函数转换。
参考样例
>>> from hscredit.core.models.losses import TopKBadCaptureLoss >>> loss = TopKBadCaptureLoss() >>> result = loss.hessian([0, 0, 1, 1], [0.1, 0.3, 0.7, 0.9])
独立业务评估指标
这些指标可单独创建并评价任意二分类模型。PSIMetric 用于参考分布与当前分布
的稳定性比较,其输入用途与其他监督指标不同。
- class hscredit.core.models.losses.AUCMetric(name='AUC曲线下面积')[源代码]
基类:
BaseMetric保持风险方向的 AUC,不会把反向模型自动翻转为高分。
参数
- 参数:
name (str) -- 指标名称,默认
"AUC曲线下面积"。
属性
greater_is_better=True;指标越大越好,有效权重下必须同时存在好、坏样本。参考样例
>>> AUCMetric()([0, 0, 1, 1], [0.1, 0.2, 0.8, 0.9]) 1.0
- class hscredit.core.models.losses.KSMetric(name='ks')[源代码]
基类:
BaseMetricKS (Kolmogorov-Smirnov) 指标.
衡量模型区分好坏客户的能力,KS值越大表示模型区分能力越强。
KS = max(|累积好客户比例 - 累积坏客户比例|)- 参数:
name (str) -- 指标名称,默认为"ks"
参考样例
>>> import numpy as np >>> from hscredit.core.models.losses import KSMetric >>> >>> ks_metric = KSMetric() >>> y_true = np.array([0, 0, 1, 1, 0, 1, 0, 1]) >>> y_pred = np.array([0.1, 0.2, 0.8, 0.9, 0.3, 0.7, 0.4, 0.6]) >>> ks_value = ks_metric(y_true, y_pred) >>> print(f"KS: {ks_value:.4f}")
>>> # 在LightGBM中使用 >>> import lightgbm as lgb >>> train_data = lgb.Dataset(X_train, label=y_train) >>> bst = lgb.train( ... params={'objective': 'binary'}, ... train_set=train_data, ... feval=ks_metric.to_lightgbm(api="native"), ... num_boost_round=100 ... )
引用
KS(Kolmogorov–Smirnov)统计量:https://en.wikipedia.org/wiki/Kolmogorov–Smirnov_test ; 其在信用评分中的应用见 Siddiqi, N. (2006). Credit Risk Scorecards. Wiley。
- class hscredit.core.models.losses.GiniMetric(name='gini', score_direction='auto')[源代码]
基类:
BaseMetricGini系数指标.
Gini = 2 * AUC - 1
衡量模型区分能力,Gini越大越好。
- 参数:
name (str) -- 指标名称,默认为"gini"
score_direction (str) -- 同
metrics.auc,默认auto;higher_risk保留原始方向
参考样例
>>> from hscredit.core.models.losses import GiniMetric >>> gini_metric = GiniMetric() >>> gini_value = gini_metric(y_true, y_pred)
- class hscredit.core.models.losses.TopKCaptureMetric(top_ratio=0.05, name='头部坏样本捕获率')[源代码]
基类:
BaseMetric高风险头部名单捕获的坏样本数占全部坏样本数的比例。
参数
- 参数:
top_ratio (float) -- 头部人数占比,范围
(0, 1],默认 0.05;人数向上取整。name (str) -- 指标名称,默认
"头部坏样本捕获率"。
属性
greater_is_better=True;没有有效坏样本时无法定义捕获率,将抛出异常。 同分边界按相同比例计入,权重用于加权坏样本数。参考样例
>>> TopKCaptureMetric(top_ratio=0.5)([0, 0, 1, 1], [0.1, 0.2, 0.8, 0.9]) 1.0
- class hscredit.core.models.losses.TopKLiftMetric(top_ratio=0.1, name='头部提升倍数')[源代码]
基类:
BaseMetric高风险头部名单坏样本率相对全量坏样本率的提升倍数。
参数
- 参数:
top_ratio (float) -- 头部人数占比,范围
(0, 1],默认 0.1;人数向上取整。name (str) -- 指标名称,默认
"头部提升倍数"。
属性
greater_is_better=True;名单和总体均使用加权坏样本率。 名单权重为零或总体没有有效坏样本时抛出异常。参考样例
>>> TopKLiftMetric(top_ratio=0.5)([0, 0, 1, 1], [0.1, 0.2, 0.8, 0.9]) 2.0
- class hscredit.core.models.losses.BadDebtMetric(approval_rate=0.3, name='通过客户坏账率')[源代码]
基类:
BaseMetric固定人数通过率下,低风险通过客户的观察坏账率。
参数
- 参数:
approval_rate (float) -- 通过人数占比,范围
(0, 1],默认 0.3;人数向上取整。name (str) -- 指标名称,默认
"通过客户坏账率"。
属性
greater_is_better=False;越小越好。边界同分样本等比例通过, 坏账率使用通过样本权重作为分母;通过样本权重为零时抛出异常。参考样例
>>> BadDebtMetric(approval_rate=0.5)([0, 0, 1, 1], [0.1, 0.2, 0.8, 0.9]) 0.0
- class hscredit.core.models.losses.ApprovalRateMetric(target_bad_debt_rate=0.05, name='坏账约束下最大通过率')[源代码]
基类:
BaseMetric观察坏账率不超过上限时,所有风险阈值中的最大通过率。
参数
- 参数:
target_bad_debt_rate (float) -- 观察坏账率上限,范围
[0, 1],默认 0.05。name (str) -- 指标名称,默认
"坏账约束下最大通过率"。
属性
greater_is_better=True;相同预测概率的客户必须同时通过。 样本权重同时用于累计通过率和累计坏账率。无可行阈值时返回 0。 此值通过标签搜索评估集上的阈值,不能作为未见数据的坏账率保证。参考样例
>>> ApprovalRateMetric(0.0)([0, 0, 1, 1], [0.1, 0.2, 0.8, 0.9]) 0.5
- class hscredit.core.models.losses.ClassificationCostMetric(fn_cost=1.0, fp_cost=1.0, threshold=0.5, name='人均误判成本')[源代码]
基类:
BaseMetric固定分类阈值下,全量样本的人均误判成本。
参数
- 参数:
fn_cost (float) -- 漏抓坏客户的单位成本,非负有限数,默认 1.0。
fp_cost (float) -- 误拒好客户的单位成本,非负有限数,默认 1.0。
threshold (float) -- 拒绝阈值,范围
[0, 1],默认 0.5;p >= threshold拒绝。name (str) -- 指标名称,默认
"人均误判成本"。
属性
greater_is_better=False;正确分类计零,错误分类按成本计入,并按样本权重平均。参考样例
>>> ClassificationCostMetric(fn_cost=100, fp_cost=1)([0, 1], [0.8, 0.2]) 50.5
- class hscredit.core.models.losses.ProfitMetric(revenue=1.0, default_cost=10.0, cutoff=0.5, name='人均审批利润')[源代码]
基类:
BaseMetric给定固定审批阈值时,全量申请客户的人均已实现利润。
参数
- 参数:
revenue (float) -- 好客户通过后的单位收益,非负有限数,默认 1.0。
default_cost (float) -- 坏客户通过后的单位损失,非负有限数,默认 10.0。
cutoff (float) -- 审批阈值,范围
[0, 1],默认 0.5;p < cutoff通过。name (str) -- 指标名称,默认
"人均审批利润"。
属性
greater_is_better=True;通过好客户计收益,通过坏客户计负损失,拒绝计零。 分母为全量样本权重,因此各模型在同一评估集上可直接比较。参考样例
>>> ProfitMetric(revenue=100, default_cost=1000)([0, 0, 1, 1], [0.1, 0.2, 0.8, 0.9]) 50.0
- class hscredit.core.models.losses.PSIMetric(expected=None, n_bins=10, name='psi')[源代码]
基类:
BaseMetricPSI (Population Stability Index) 指标.
衡量样本分布的稳定性,常用于模型监控。
PSI = sum((实际占比 - 期望占比) * ln(实际占比/期望占比))
- 参数:
expected (ndarray | None) -- 基准预测分数的一维非空有限数组,默认 None, 为 None 时需要在 __call__ 中提供;不要求与当前样本等长。
n_bins (int) -- 基准分位分箱的最大数量,整数且至少为 2,默认 10。
name (str) -- 指标名称,默认为"psi"
参考样例
>>> from hscredit.core.models.losses import PSIMetric >>> >>> # 使用训练集作为基准 >>> psi_metric = PSIMetric(expected=y_train_pred, n_bins=10) >>> >>> # 计算测试集的PSI >>> psi_value = psi_metric(y_test, y_test_pred) >>> print(f"PSI: {psi_value:.4f}")
注意
复用
hscredit.core.metrics.psi的冻结基准分箱,不丢弃落在基准 最小值和最大值之外的样本。低基数或常量基准遵循公共 PSI 的类别口径。 本指标不支持样本权重;它衡量分布漂移,不能单独代替 AUC 等区分度指标。PSI解释: - PSI < 0.1: 分布稳定 - 0.1 <= PSI < 0.25: 分布有轻微变化 - PSI >= 0.25: 分布变化显著,需要关注
框架适配器
一般优先使用 loss.to_xgboost(api=...)、loss.to_lightgbm(api=...)、
loss.to_catboost() 或 loss.ngboost_params()。
CatBoost、NGBoost 与 TabNet 的损失必须可安全逐样本或分批计算;具体限制见使用指南。
- class hscredit.core.models.XGBoostLossAdapter(loss)[源代码]
基类:
objectXGBoost 目标与配套指标,默认使用原生 train 接口。
参数
- 参数:
loss (BaseLoss) -- BaseLoss 实例,训练接收一维原始分数并自动处理样本权重。
属性
loss保存目标对象;指标默认使用独立的损失参数快照。参考样例
>>> from hscredit.core.models.losses import FocalLoss, XGBoostLossAdapter >>> adapter = XGBoostLossAdapter(FocalLoss(alpha=0.75)) >>> objective = adapter.objective(api='sklearn') >>> eval_metric = adapter.metric(api='sklearn')
- objective(api='native')[源代码]
生成训练目标。
- 参数:
api --
'native'接收 (preds, DMatrix),'sklearn'接收 (y_true, y_pred, sample_weight=None);预测均为原始分数。- 返回:
回调,返回对原始分数求导的 (grad, hess) 数组。
>>> from hscredit.core.models.losses import FocalLoss, XGBoostLossAdapter >>> objective = XGBoostLossAdapter(FocalLoss()).objective()
- metric(metric=None, api='native')[源代码]
生成配合本自定义目标使用的评估回调,自动转换原始分数。
- 参数:
metric -- BaseMetric 实例,默认
loss.metric()。api --
'native'或'sklearn',须与训练接口相同。
- 返回:
native 返回 (name, value),sklearn 返回 value 的回调。 不改变指标符号,早停方向须按 metric.greater_is_better 配置。
>>> from hscredit.core.models.losses import FocalLoss, AUCMetric, XGBoostLossAdapter >>> callback = XGBoostLossAdapter(FocalLoss()).metric(AUCMetric())
- class hscredit.core.models.LightGBMLossAdapter(loss)[源代码]
基类:
objectLightGBM 目标与配套指标,原生 train 需指定 api='native'。
参数
- 参数:
loss (BaseLoss) -- BaseLoss 实例,训练输入为一维原始分数。
属性
loss保存损失对象,样本权重与链接函数由目标回调统一处理。参考样例
>>> from hscredit.core.models.losses import FocalLoss, LightGBMLossAdapter >>> adapter = LightGBMLossAdapter(FocalLoss()) >>> objective, eval_metric = adapter.objective(), adapter.metric()
- objective(api='sklearn')[源代码]
生成接收原始分数并返回 (grad, hess) 的训练回调。
- 参数:
api -- 默认
'sklearn'接收 (y_true, y_pred, sample_weight=None);'native'接收 (preds, Dataset),用于 params['objective']。- 返回:
目标回调,自动应用 sigmoid 和数据集权重。
>>> from hscredit.core.models.losses import FocalLoss, LightGBMLossAdapter >>> objective = LightGBMLossAdapter(FocalLoss()).objective(api='native')
- metric(metric=None, api='sklearn')[源代码]
生成自动转换原始分数的评估回调,和自定义目标配套使用。
- 参数:
metric -- BaseMetric 实例,默认
loss.metric()。api --
'sklearn'或'native',须与训练接口相同。
- 返回:
回调,返回 (name, value, greater_is_better)。
>>> from hscredit.core.models.losses import FocalLoss, KSMetric, LightGBMLossAdapter >>> callback = LightGBMLossAdapter(FocalLoss()).metric(KSMetric())
- class hscredit.core.models.CatBoostLossAdapter(loss)[源代码]
基类:
objectCatBoost 逐样本损失与配套指标。
参数
- 参数:
loss (BaseLoss) -- 支持独立逐行计算的 BaseLoss,例如固定类别权重的 FocalLoss。
属性
loss保存损失对象;非可加损失会在生成训练目标时拒绝。参考样例
>>> from hscredit.core.models.losses import FocalLoss, CatBoostLossAdapter >>> adapter = CatBoostLossAdapter(FocalLoss()) >>> objective, eval_metric = adapter.objective(), adapter.metric()
- objective()[源代码]
生成 CatBoost 目标对象。
- 返回:
对象,calc_ders_range 接收原始分数、0/1 标签和可选权重, 输出逐样本 (-grad, -hess),符合 CatBoost 的符号约定。
- 抛出:
ValueError -- 损失依赖全量排序、动态类别权重或绑定逐行数组。
>>> from hscredit.core.models.losses import FocalLoss, CatBoostLossAdapter >>> objective = CatBoostLossAdapter(FocalLoss()).objective()
- metric(metric=None)[源代码]
生成 CatBoost 指标对象,按全量验证集保留指标语义。
- 参数:
metric -- BaseMetric 实例,默认 loss.metric()。
- 返回:
对象,evaluate 接收原始分数并返回 (误差和, 权重和), get_final_error 还原指标值,is_max_optimal 返回优化方向。
>>> from hscredit.core.models.losses import FocalLoss, CatBoostLossAdapter >>> callback = CatBoostLossAdapter(FocalLoss()).metric()
- class hscredit.core.models.TabNetLossAdapter(loss)[源代码]
基类:
objectTabNet损失函数适配器.
将自定义损失函数转换为PyTorch可用的格式,适用于TabNet。
- 参数:
loss (BaseLoss) -- 损失函数对象
参考样例
>>> from pytorch_tabnet.tab_model import TabNetClassifier >>> from hscredit.core.models.losses import FocalLoss, TabNetLossAdapter >>> >>> loss = FocalLoss(alpha=0.75, gamma=2.0) >>> adapter = TabNetLossAdapter(loss) >>> >>> model = TabNetClassifier() >>> model.fit( ... X_train, y_train, ... loss_fn=adapter.loss_fn(), ... max_epochs=100 ... )
注意
TabNet使用PyTorch,因此需要PyTorch环境。
- loss_fn()[源代码]
获取支持 PyTorch 反向传播的二分类损失模块。
- 返回:
nn.Module,调用签名为 (y_pred, y_true)。y_pred 是一维、 单列或两列原始 logits,y_true 是同批 0/1 标签;返回平均损失张量。 NumPy 计算的解析梯度由自定义 autograd 返回到 logits。- 抛出:
ImportError -- 未安装 PyTorch。
ValueError -- 损失依赖全量排序、动态类别权重或绑定样本数组。
>>> from hscredit.core.models.losses import FocalLoss, TabNetLossAdapter >>> loss_fn = TabNetLossAdapter(FocalLoss()).loss_fn()
- class hscredit.core.models.losses.NGBoostLossAdapter(loss)[源代码]
基类:
objectNGBoost损失函数适配器.
将自定义损失函数转换为NGBoost可用的Score类。
NGBoost使用自然梯度 + 概率分布框架,与XGBoost/LightGBM的
(grad, hess)接口完全不同。本适配器通过链式法则将BaseLoss的梯度(对概率 p 求导) 转换为NGBoost所需的分布参数梯度(对 logit 求导):dL/d(logit) = dL/dp × dp/d(logit) = dL/dp × p × (1 - p)
- 参数:
loss (BaseLoss) -- 损失函数对象
参考样例
>>> from ngboost import NGBClassifier >>> from hscredit.core.models.losses import ExpectedProfitLoss, NGBoostLossAdapter >>> >>> loss = ExpectedProfitLoss(revenue=100, default_cost=1000) >>> adapter = NGBoostLossAdapter(loss) >>> >>> model = NGBClassifier( ... **loss.ngboost_params(), ... n_estimators=500, ... learning_rate=0.01 ... ) >>> model.fit(X_train, y_train)
注意
仅支持二分类 Bernoulli 分布;需使用本损失提供的分布子类。
score()与d_score()使用同一个自定义损失d_score()使用自定义loss的梯度驱动自然梯度更新推荐使用
loss.ngboost_params()同时配套 Score 与 Dist。
- score_class()[源代码]
生成 NGBoost Score 子类,必须搭配返回类的 distribution。
- 返回:
Score 类,score 返回逐行损失,d_score 返回 logit 导数, metric 返回 Bernoulli Fisher 信息;不直接接收框架外部预测。
- 抛出:
ImportError -- 未安装 NGBoost。
ValueError -- 损失不支持独立逐行计算。
>>> from hscredit.core.models.losses import FocalLoss, NGBoostLossAdapter >>> from ngboost import NGBClassifier >>> score = NGBoostLossAdapter(FocalLoss()).score_class() >>> model = NGBClassifier(Score=score, Dist=score.distribution)