损失函数与评估指标

每一种损失都通过 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)
ngboost_params()[源代码]

生成可直接解包给 NGBClassifier 的配套参数。

返回:

字典,包含相互兼容的 Score 和 Dist 类。

抛出:
  • ImportError -- NGBoost 未安装。

  • ValueError -- 损失不支持独立逐行计算。

>>> from hscredit.core.models.losses import FocalLoss
>>> from ngboost import NGBClassifier
>>> model = NGBClassifier(**FocalLoss().ngboost_params())
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')[源代码]

基类:BaseLoss

Focal 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):

  1. 有效样本数加权: 基于 Class-Balanced Loss 论文,用 E_n = (1 - β^n) / (1 - β) 自动计算正负样本权重, 比手动设置 alpha 更鲁棒。

  2. 标签平滑: 将硬标签 {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=...) 创建副本,避免覆盖训练金额。

返回类型:

AmountWeightedLoss

>>> 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,原地更新;数组须有限且与之后计算的样本顺序一致。

返回类型:

ExpectedValueLoss

>>> 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 的增强版本,核心改进:

  1. 平方铰链代理: max(0, margin - Δ)² 比 logistic 代理 log(1+exp(-Δ)) 使用不同的间隔惩罚;效果需在验证集比较。

  2. 硬负例挖掘: 优先选择违反 margin 的样本对(p_pos - p_neg < margin), 避免在已充分排序的 pair 上浪费梯度。

  3. 固定 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

gradient(y_true, y_pred)[源代码]

计算梯度。

平方铰链梯度:

dL/dp_i = -2 × max(0, m - Δ_ij)   (对 pos 样本 i)
dL/dp_j =  2 × max(0, m - Δ_ij)   (对 neg 样本 j)
参数:
  • y_true (ndarray) -- 真实标签

  • y_pred (ndarray) -- 预测概率

返回:

梯度数组, shape (n_samples,)

返回类型:

ndarray

hessian(y_true, y_pred)[源代码]

计算二阶导数。

参数:
  • y_true (ndarray) -- 真实标签

  • y_pred (ndarray) -- 预测概率

返回:

二阶导数数组, shape (n_samples,)

返回类型:

ndarray

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')[源代码]

基类:BaseLoss

KS 导向损失函数,强化好坏样本预测分布的分离能力。

KS(Kolmogorov-Smirnov)统计量衡量正负样本累积分布的最大距离, 是信贷风控模型评估的核心指标之一。本损失在标准交叉熵基础上增加 分布分离惩罚项,通过以下机制逼近 KS 优化:

  1. 均值分离: 最大化 mean(p|y=1) - mean(p|y=0)

  2. 分布聚集: 减小类内预测方差,使分布更集中

  3. 重叠区聚焦: 在正负分布重叠区域施加更大权重

数学形式:

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')[源代码]

基类:BaseLoss

Top-K 坏样本捕获损失,优化头部 k% 的坏样本召回率。

在策略、催收、反欺诈名单筛选场景中,核心目标是在有限资源 (如 top 5% 的高风险名单)下尽可能多地覆盖坏样本。本损失 直接面向该业务目标构造代理。分位数使用线性插值,其依赖纳入导数; 排序切换和同分边界处不可微。Hessian 只返回对角项,框架忽略跨样本项。

核心机制:

  1. 计算预测分布的 top-k 分位阈值

  2. 通过 sigmoid 软门控判断每个样本是否 "进入" 头部

  3. 对未进入头部的坏样本(漏捕)施加重惩罚

  4. 对进入头部的好样本(误报)施加轻惩罚

数学形式:

τ_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')[源代码]

基类:BaseMetric

KS (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')[源代码]

基类:BaseMetric

Gini系数指标.

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')[源代码]

基类:BaseMetric

PSI (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)[源代码]

基类:object

XGBoost 目标与配套指标,默认使用原生 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)[源代码]

基类:object

LightGBM 目标与配套指标,原生 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)[源代码]

基类:object

CatBoost 逐样本损失与配套指标。

参数

参数:

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)[源代码]

基类:object

TabNet损失函数适配器.

将自定义损失函数转换为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)[源代码]

基类:object

NGBoost损失函数适配器.

将自定义损失函数转换为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)