损失函数
自定义风控损失函数(继承 BaseLoss)通过框架适配器接入 XGBoost / LightGBM /
CatBoost / TabNet。
- class hscredit.core.models.BaseLoss(name='custom_loss')[源代码]
基类:
ABC损失函数基类。
所有自定义损失函数都应该继承此类,并实现以下方法: -
__call__: 计算损失值 -gradient: 计算梯度(一阶导数 dL/dp,相对**概率** p) -hessian: 计算二阶导数(可选,用于 XGBoost 等需要二阶导的框架)适配器模式(框架转换)
子类只需以"概率 p"为视角实现
gradient/hessian,再用以下便捷方法转换为各 boosting 框架所需格式——内部统一处理 sigmoid 链接函数(原始分数→概率)与各框架的 符号/接口约定:to_xgboost():返回obj(preds, dtrain) -> (grad, hess)闭包to_lightgbm():返回obj(y_true, y_pred) -> (grad, hess)闭包to_catboost():返回实现calc_ders_range的损失对象to_ngboost():返回 NGBoostScore子类(仅 Bernoulli 二分类)
- 参数:
name (str) -- 损失函数名称,默认为
"custom_loss"
参考样例
>>> import xgboost as xgb >>> from hscredit.core.models.losses import FocalLoss >>> loss = FocalLoss(gamma=2.0, alpha=0.25) >>> booster = xgb.train({'disable_default_eval_metric': 1}, dtrain, ... obj=loss.to_xgboost()) # 自定义目标
- abstractmethod gradient(y_true, y_pred)[源代码]
计算梯度(一阶导数)。
- 参数:
y_true (ndarray) -- 真实标签
y_pred (ndarray) -- 预测值
- 返回:
梯度数组, shape (n_samples,)
- 返回类型:
ndarray
- hessian(y_true, y_pred)[源代码]
计算二阶导数(可选)。
某些框架如XGBoost需要二阶导数,如果不需要可以返回None
- 参数:
y_true (ndarray) -- 真实标签
y_pred (ndarray) -- 预测值
- 返回:
二阶导数数组, shape (n_samples,), 或None
- 返回类型:
ndarray | None
- to_catboost()[源代码]
转换为CatBoost格式的损失函数对象。
CatBoost 自定义损失需要一个实现
calc_ders_range接口的对象(而非普通 函数),可直接传给CatBoostClassifier(loss_function=...)。本方法委托给CatBoostLossAdapter,内部已 完成 sigmoid 链接函数转换与 CatBoost 的符号约定处理。- 返回:
CatBoost 可用的损失对象(含 calc_ders_range 方法)
- to_ngboost()[源代码]
转换为NGBoost格式的Score类(仅支持 Bernoulli 二分类)。
NGBoost 使用自然梯度 + 概率分布框架,自定义 loss 需要实现 Score 子类。 本方法通过链式法则将 ``dL/dp``(BaseLoss.gradient 的输出)转换为 ``dL/d(logit)``(NGBoost 需要的分布参数梯度):
dL/d(logit) = dL/dp × dp/d(logit) = dL/dp × p × (1 - p)
- 返回:
NGBoost Score 子类(未实例化),可直接传给
NGBClassifier(Score=...)
参考样例
>>> from ngboost import NGBClassifier >>> from hscredit.core.models.losses import ExpectedProfitLoss >>> >>> loss = ExpectedProfitLoss(revenue=100, default_cost=1000) >>> model = NGBClassifier( ... Score=loss.to_ngboost(), ... n_estimators=500, ... learning_rate=0.01 ... ) >>> model.fit(X_train, y_train)
注意
仅支持 ``Dist=Bernoulli``(NGBoost 默认二分类分布)
score()使用标准 BCE 作为监控指标d_score()使用自定义 loss 的梯度驱动参数更新
- 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
- 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)。
- 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 >>> >>> # 在LightGBM中使用 >>> import lightgbm as lgb >>> train_data = lgb.Dataset(X_train, label=y_train) >>> bst = lgb.train( ... params={'objective': 'binary'}, ... train_set=train_data, ... fobj=loss.to_lightgbm(), ... 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。
- 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
- class hscredit.core.models.BadDebtLoss(target_approval_rate=0.3, bad_debt_weight=1.0, approval_weight=0.5, name='bad_debt_loss')[源代码]
基类:
BaseLoss坏账率优化损失函数,最小化坏账率同时保持通过率在合理水平。
适用于信贷审批场景,希望降低通过客户的坏账比例。
- 参数:
target_approval_rate (float) -- 目标通过率,默认为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 ... ) >>> >>> # 在CatBoost中使用 >>> from catboost import CatBoostClassifier >>> model = CatBoostClassifier( ... iterations=1000, ... loss_function=loss.to_catboost(), ... eval_metric='AUC' ... )
引用
在目标通过率约束下最小化坏账率,属信贷审批的业务驱动目标;成本敏感学习背景见 Elkan, C. (2001). The Foundations of Cost-Sensitive Learning. IJCAI 2001。
- class hscredit.core.models.ApprovalRateLoss(target_bad_debt_rate=0.05, name='approval_rate_loss')[源代码]
基类:
BaseLoss通过率优化损失函数,在保证坏账率不超过目标的前提下最大化通过率。
- 参数:
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)
- class hscredit.core.models.ProfitMaxLoss(interest_income=1.0, bad_debt_loss=10.0, name='profit_max_loss')[源代码]
基类:
BaseLoss利润最大化损失函数,综合考虑坏账损失和利息收益最大化总利润。
利润模型: 利润 = 通过客户数 * (利息收益 - 坏账率 * 坏账损失)
- 参数:
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)
- 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)。
- 参数:
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)。
- 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
- class hscredit.core.models.XGBoostLossAdapter(loss)[源代码]
基类:
objectXGBoost损失函数适配器.
将自定义损失函数转换为XGBoost可用的格式。
- 参数:
loss (BaseLoss) -- 损失函数对象
参考样例
>>> import xgboost as xgb >>> from hscredit.core.models.losses import FocalLoss, XGBoostLossAdapter >>> >>> # 创建损失函数 >>> loss = FocalLoss(alpha=0.75, gamma=2.0) >>> adapter = XGBoostLossAdapter(loss) >>> >>> # 在XGBoost中使用 >>> dtrain = xgb.DMatrix(X_train, label=y_train) >>> params = { ... 'objective': 'binary:logistic', ... 'eval_metric': 'auc' ... } >>> bst = xgb.train( ... params, ... dtrain, ... obj=adapter.objective(), ... num_boost_round=100 ... )
- metric(metric)[源代码]
获取XGBoost评估指标.
- 参数:
metric (BaseMetric) -- 评估指标对象
- 返回:
XGBoost格式的评估指标
- 返回类型:
Callable
- class hscredit.core.models.LightGBMLossAdapter(loss)[源代码]
基类:
objectLightGBM损失函数适配器.
将自定义损失函数转换为LightGBM可用的格式。
- 参数:
loss (BaseLoss) -- 损失函数对象
参考样例
>>> import lightgbm as lgb >>> from hscredit.core.models.losses import CostSensitiveLoss, LightGBMLossAdapter >>> >>> loss = CostSensitiveLoss(fn_cost=100, fp_cost=1) >>> adapter = LightGBMLossAdapter(loss) >>> >>> train_data = lgb.Dataset(X_train, label=y_train) >>> # objective() 采用 (y_true, y_pred) -> (grad, hess) 约定, >>> # 通过 params['objective'] 传入(LightGBM 4.0 起已移除 fobj 参数) >>> bst = lgb.train( ... params={'objective': adapter.objective(), 'metric': 'auc'}, ... train_set=train_data, ... num_boost_round=100 ... )
- metric(metric)[源代码]
获取LightGBM评估指标.
- 参数:
metric (BaseMetric) -- 评估指标对象
- 返回:
LightGBM格式的评估指标
- 返回类型:
Callable
- class hscredit.core.models.CatBoostLossAdapter(loss)[源代码]
基类:
objectCatBoost损失函数适配器.
将自定义损失函数转换为CatBoost可用的格式。
- 参数:
loss (BaseLoss) -- 损失函数对象
参考样例
>>> from catboost import CatBoostClassifier >>> from hscredit.core.models.losses import BadDebtLoss, CatBoostLossAdapter >>> >>> loss = BadDebtLoss(target_approval_rate=0.3) >>> adapter = CatBoostLossAdapter(loss) >>> >>> model = CatBoostClassifier( ... iterations=1000, ... loss_function=adapter.objective(), ... eval_metric='AUC' ... ) >>> model.fit(X_train, y_train)
- metric(metric)[源代码]
获取CatBoost评估指标.
- 参数:
metric (BaseMetric) -- 评估指标对象
- 返回:
CatBoost格式的评估指标类
- 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环境。