自定义目标函数 #
自定义目标函数概述 #
为什么需要自定义? #
text
┌─────────────────────────────────────────────────────────────┐
│ 自定义目标函数场景 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 特定业务需求 │
│ - 不平衡分类的成本敏感损失 │
│ - 回归任务的加权损失 │
│ - 排序任务的自定义指标 │
│ │
│ 2. 研究创新 │
│ - 新的损失函数设计 │
│ - 论文算法实现 │
│ - 实验性目标函数 │
│ │
│ 3. 特殊优化目标 │
│ - 分位数回归 │
│ - 置信区间预测 │
│ - 多目标优化 │
│ │
└─────────────────────────────────────────────────────────────┘
目标函数要求 #
XGBoost 的自定义目标函数需要返回一阶和二阶梯度:
python
def custom_objective(preds, dtrain):
"""
自定义目标函数
参数:
- preds: 模型预测值(原始输出,未经 sigmoid/softmax)
- dtrain: DMatrix 对象
返回:
- grad: 一阶导数(梯度)
- hess: 二阶导数(海森矩阵对角元素)
"""
labels = dtrain.get_label()
# 计算梯度和海森
grad = ... # 一阶导数
hess = ... # 二阶导数
return grad, hess
常见目标函数实现 #
二分类 - Log Loss #
python
import numpy as np
import xgboost as xgb
def logloss_objective(preds, dtrain):
"""
二分类 Log Loss 目标函数
L = -[y*log(p) + (1-y)*log(1-p)]
p = sigmoid(preds)
一阶导数: ∂L/∂preds = p - y
二阶导数: ∂²L/∂preds² = p * (1 - p)
"""
labels = dtrain.get_label()
# Sigmoid
preds = 1.0 / (1.0 + np.exp(-preds))
# 梯度和海森
grad = preds - labels
hess = preds * (1.0 - preds)
return grad, hess
# 使用自定义目标函数
dtrain = xgb.DMatrix(X_train, label=y_train)
params = {'max_depth': 6, 'eta': 0.1}
model = xgb.train(params, dtrain, num_boost_round=100, obj=logloss_objective)
多分类 - Softmax Loss #
python
def softmax_objective(preds, dtrain, num_class):
"""
多分类 Softmax 目标函数
preds: shape = (n_samples * num_class,)
"""
labels = dtrain.get_label()
# 重塑预测值
preds = preds.reshape(-1, num_class)
# Softmax
max_preds = np.max(preds, axis=1, keepdims=True)
exp_preds = np.exp(preds - max_preds)
probs = exp_preds / np.sum(exp_preds, axis=1, keepdims=True)
# One-hot 编码标签
y_onehot = np.zeros_like(probs)
y_onehot[np.arange(len(labels)), labels.astype(int)] = 1
# 梯度和海森
grad = (probs - y_onehot).flatten()
hess = (probs * (1 - probs)).flatten()
return grad, hess
回归 - Huber Loss #
python
def huber_objective(preds, dtrain, delta=1.0):
"""
Huber Loss 目标函数
对异常值更鲁棒
"""
labels = dtrain.get_label()
residual = preds - labels
abs_residual = np.abs(residual)
# 梯度
grad = np.where(
abs_residual <= delta,
residual,
delta * np.sign(residual)
)
# 海森
hess = np.where(
abs_residual <= delta,
np.ones_like(residual),
np.zeros_like(residual)
)
return grad, hess
分位数回归 #
python
def quantile_objective(preds, dtrain, alpha=0.5):
"""
分位数回归目标函数
参数:
- alpha: 分位数 (0.5 = 中位数)
"""
labels = dtrain.get_label()
residual = labels - preds
# 梯度
grad = np.where(
residual > 0,
-alpha,
alpha - 1
)
# 海森(分位数损失在非零点不可导,使用常数)
hess = np.ones_like(residual)
return grad, hess
# 使用示例:预测 0.25, 0.5, 0.75 分位数
params = {'max_depth': 6, 'eta': 0.1}
# 25% 分位数
model_q25 = xgb.train(params, dtrain, num_boost_round=100,
obj=lambda p, d: quantile_objective(p, d, 0.25))
# 中位数
model_q50 = xgb.train(params, dtrain, num_boost_round=100,
obj=lambda p, d: quantile_objective(p, d, 0.5))
# 75% 分位数
model_q75 = xgb.train(params, dtrain, num_boost_round=100,
obj=lambda p, d: quantile_objective(p, d, 0.75))
自定义评估指标 #
评估函数格式 #
python
def custom_eval(preds, dtrain):
"""
自定义评估指标
参数:
- preds: 预测值
- dtrain: DMatrix 对象
返回:
- (指标名称, 指标值)
"""
labels = dtrain.get_label()
# 计算指标
metric_value = ...
return 'metric_name', metric_value
常见评估指标 #
python
from sklearn.metrics import f1_score, precision_score, recall_score
def f1_eval(preds, dtrain):
"""F1 Score 评估"""
labels = dtrain.get_label()
preds_binary = (preds > 0.5).astype(int)
f1 = f1_score(labels, preds_binary)
return 'f1', f1
def precision_eval(preds, dtrain):
"""Precision 评估"""
labels = dtrain.get_label()
preds_binary = (preds > 0.5).astype(int)
prec = precision_score(labels, preds_binary)
return 'precision', prec
def recall_eval(preds, dtrain):
"""Recall 评估"""
labels = dtrain.get_label()
preds_binary = (preds > 0.5).astype(int)
rec = recall_score(labels, preds_binary)
return 'recall', rec
# 使用自定义评估指标
model = xgb.train(
params,
dtrain,
num_boost_round=100,
obj=logloss_objective,
feval=f1_eval,
evals=[(dtrain, 'train'), (dtest, 'test')]
)
自定义 AUC 评估 #
python
from sklearn.metrics import roc_auc_score
def auc_eval(preds, dtrain):
"""AUC 评估"""
labels = dtrain.get_label()
auc = roc_auc_score(labels, preds)
return 'auc', auc
# 使用
model = xgb.train(
params,
dtrain,
num_boost_round=100,
evals=[(dtest, 'eval')],
feval=auc_eval
)
高级自定义目标函数 #
成本敏感损失 #
python
def cost_sensitive_objective(preds, dtrain, cost_fp=1.0, cost_fn=5.0):
"""
成本敏感损失函数
参数:
- cost_fp: 假阳性成本
- cost_fn: 假阴性成本
"""
labels = dtrain.get_label()
# Sigmoid
preds = 1.0 / (1.0 + np.exp(-preds))
# 加权梯度
weights = np.where(labels == 1, cost_fn, cost_fp)
grad = weights * (preds - labels)
hess = weights * preds * (1.0 - preds)
return grad, hess
# 使用示例:假阴性成本更高
model = xgb.train(
params,
dtrain,
num_boost_round=100,
obj=lambda p, d: cost_sensitive_objective(p, d, cost_fp=1.0, cost_fn=5.0)
)
Focal Loss #
python
def focal_loss_objective(preds, dtrain, gamma=2.0, alpha=0.25):
"""
Focal Loss 目标函数
用于处理类别不平衡
FL = -α(1-p)^γ * y*log(p) - (1-α)*p^γ * (1-y)*log(1-p)
"""
labels = dtrain.get_label()
# Sigmoid
p = 1.0 / (1.0 + np.exp(-preds))
# Focal Loss 梯度
pt = np.where(labels == 1, p, 1 - p)
at = np.where(labels == 1, alpha, 1 - alpha)
grad = at * (1 - pt) ** gamma * (pt - labels)
hess = at * (1 - pt) ** (gamma - 1) * pt * (1 - pt) * (
gamma * (pt - labels) + (1 - pt)
)
return grad, hess
# 使用示例
model = xgb.train(
params,
dtrain,
num_boost_round=100,
obj=lambda p, d: focal_loss_objective(p, d, gamma=2.0, alpha=0.25)
)
平滑 L1 Loss #
python
def smooth_l1_objective(preds, dtrain, beta=1.0):
"""
Smooth L1 Loss (Huber Loss 变体)
更平滑的损失函数
"""
labels = dtrain.get_label()
diff = preds - labels
abs_diff = np.abs(diff)
# 梯度
grad = np.where(
abs_diff < beta,
diff / beta,
np.sign(diff)
)
# 海森
hess = np.where(
abs_diff < beta,
np.ones_like(diff) / beta,
np.zeros_like(diff)
)
return grad, hess
完整示例 #
自定义目标函数完整流程 #
python
import numpy as np
import xgboost as xgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, roc_auc_score
# 创建数据
X, y = make_classification(n_samples=10000, n_features=20, weights=[0.9, 0.1], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
# 自定义目标函数
def weighted_logloss_objective(preds, dtrain, weight_positive=5.0):
"""加权 Log Loss"""
labels = dtrain.get_label()
p = 1.0 / (1.0 + np.exp(-preds))
weights = np.where(labels == 1, weight_positive, 1.0)
grad = weights * (p - labels)
hess = weights * p * (1.0 - p)
return grad, hess
# 自定义评估指标
def weighted_accuracy_eval(preds, dtrain, threshold=0.5):
"""加权准确率评估"""
labels = dtrain.get_label()
preds_binary = (preds > threshold).astype(int)
# 计算加权准确率
weights = np.where(labels == 1, 5.0, 1.0)
correct = (preds_binary == labels).astype(float)
weighted_acc = np.sum(weights * correct) / np.sum(weights)
return 'weighted_acc', weighted_acc
# 训练
params = {'max_depth': 6, 'eta': 0.1}
model = xgb.train(
params,
dtrain,
num_boost_round=200,
obj=lambda p, d: weighted_logloss_objective(p, d, weight_positive=5.0),
feval=weighted_accuracy_eval,
evals=[(dtrain, 'train'), (dtest, 'test')],
early_stopping_rounds=20,
verbose_eval=20
)
# 评估
y_pred = model.predict(dtest)
y_pred_binary = (y_pred > 0.5).astype(int)
print(f"\n准确率: {accuracy_score(y_test, y_pred_binary):.4f}")
print(f"AUC: {roc_auc_score(y_test, y_pred):.4f}")
自定义目标函数最佳实践 #
python
def custom_objective_best_practices():
"""
自定义目标函数最佳实践
"""
practices = {
'数学推导': [
'确保目标函数可导',
'正确计算一阶和二阶导数',
'验证梯度计算正确性'
],
'实现细节': [
'处理数值稳定性问题',
'避免除零错误',
'使用 clip 限制数值范围'
],
'调试技巧': [
'与内置目标函数对比',
'使用数值梯度验证',
'监控训练过程'
],
'性能优化': [
'使用向量化计算',
'避免循环操作',
'利用 NumPy 广播'
]
}
for category, items in practices.items():
print(f"\n{category}:")
for item in items:
print(f" • {item}")
custom_objective_best_practices()
下一步 #
现在你已经掌握了自定义目标函数,接下来学习 分类任务 开始实战应用!
最后更新:2026-04-04