XGBOOST自定义损失函数

以二分类的交叉熵损失函数为例

1、直接使用XGB中定义好的交叉熵损失函数

import xgboost as xgb
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np
import random
import os

seed = 1
random.seed(seed)
np.random.seed(seed)
os.environ['PYTHONHASHSEED'] = str(seed)

# 加载数据集
data = load_breast_cancer()
X = data.data
y = data.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# 转换数据格式为DMatrix
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)


# 设置模型参数
params = {
    'objective': 'binary:logistic',  # 二分类逻辑回归
    'eval_metric': 'error',  # 评估指标为错误率
    'seed': seed
}

# 训练模型
num_rounds = 100  # 迭代次数
model = xgb.train(params, dtrain, num_rounds)

# 预测
y_pred = model.predict(dtest)
y_pred_binary = [1 if p > 0.1 else 0 for p in y_pred]  # 将概率转换为类别

# 计算准确率
accuracy = accuracy_score(y_test, y_pred_binary)
print("Accuracy:", accuracy)


最终的运行结果为

Accuracy: 0.9210526315789473

2、使用自定义的交叉熵损失函数

import xgboost as xgb
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np
import random
import os

seed = 1
random.seed(seed)
np.random.seed(seed)
os.environ['PYTHONHASHSEED'] = str(seed)

# 加载数据集
data = load_breast_cancer()
X = data.data
y = data.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# 转换数据格式为DMatrix
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)

def custom_loss(preds, dtrain):
    labels = dtrain.get_label()

    preds = 1.0 / (1.0 + np.exp(-preds))

    def binary_cross_entropy_gradient(y_pred, y_true):
        eps = 1e-15  # 避免除零错误的常数

        # 预测概率取值范围限制在 [eps, 1-eps] 内
        y_pred = np.clip(y_pred, eps, 1 - eps)

        # 二分类交叉熵损失函数的一阶导数(梯度)
        gradient = - y_true / y_pred + (1 - y_true) / (1 - y_pred)

        return gradient

    def binary_cross_entropy_hessian(y_pred, y_true):
        eps = 1e-15  # 避免除零错误的常数

        # 预测概率取值范围限制在 [eps, 1-eps] 内
        y_pred = np.clip(y_pred, eps, 1 - eps)

        # 二分类交叉熵损失函数的二阶导数(海森矩阵)
        hessian = y_true / (y_pred ** 2) + (1 - y_true) / ((1 - y_pred) ** 2)

        return hessian

    gradient = binary_cross_entropy_gradient(preds, labels)
    hessian = binary_cross_entropy_hessian(preds, labels)

    # 防止梯度爆炸做剪裁
    l2 = np.linalg.norm(gradient)
    max_norm = 0.43
    if l2>max_norm:
        gradient = gradient*(max_norm/l2)
    l2 = np.linalg.norm(hessian)
    if l2>max_norm:
        hessian = hessian*(max_norm/l2)

    return gradient, hessian

# 设置模型参数
params = {
    'eval_metric': 'error',  # 评估指标为错误率
    'seed': seed
}

# 训练模型
num_rounds = 100  # 迭代次数
model = xgb.train(params, dtrain, num_rounds,obj=custom_loss)

# 预测
y_pred = model.predict(dtest)
y_pred_binary = [1 if p > 0.1 else 0 for p in y_pred]  # 将概率转换为类别

# 计算准确率
accuracy = accuracy_score(y_test, y_pred_binary)
print("Accuracy:", accuracy)


Accuracy: 0.9122807017543859

3、AUC不一致的原因猜测

可能是对梯度爆炸或者消失时的处理机制不一致造成的

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
XGBoost是一种常用的梯度提升框架,在分类和回归问题中具有广泛的应用。它是一种基于决策树的模型,通过迭代地提高每个决策树的预测能力,最终得到一个强大的集成模型。XGBoost支持自定义损失函数,使得用户可以根据自己的需求来定义损失函数。 在XGBoost中,损失函数的定义是通过构建一个二阶泰勒展开式得到的。具体而言,假设我们要定义一个自定义损失函数$L(y,\hat{y})$,其中$y$是真实值,$\hat{y}$是预测值。那么,我们可以通过以下方式来构建损失函数: 1. 定义一阶导数和二阶导数 $$ g_i=\frac{\partial L(y_i,\hat{y}_i)}{\partial \hat{y}_i}\\ h_i=\frac{\partial^2 L(y_i,\hat{y}_i)}{\partial \hat{y}_i^2} $$ 其中$i$表示样本的索引,$g_i$是损失函数$L(y_i,\hat{y_i})$在$\hat{y_i}$处的一阶导数,$h_i$是损失函数$L(y_i,\hat{y_i})$在$\hat{y_i}$处的二阶导数。 2. 在XGBoost的目标函数中引入自定义损失函数 $$ Obj(\theta)=\sum_{i=1}^nl(y_i,\hat{y}_i)+\sum_{i=1}^t\Omega(f_i)+\gamma T $$ 其中$l(y_i,\hat{y}_i)$是样本$i$的损失函数,$\Omega(f_i)$是树$f_i$的正则化项,$\gamma$是正则化参数,$T$是树的数量。对于分类问题,$l(y_i,\hat{y}_i)$可以是对数似然损失函数或指数损失函数等;对于回归问题,$l(y_i,\hat{y}_i)$可以是平方损失函数或绝对损失函数等。 3. 将自定义损失函数表示成$g_i$和$h_i$的形式 为了将自定义损失函数$L(y,\hat{y})$表示成$g_i$和$h_i$的形式,我们需要对$L(y,\hat{y})$进行二阶泰勒展开: $$ L(y,\hat{y})\approx \sum_{i=1}^n\left[L(y_i,\hat{y}_i)+g_i(\hat{y}_i-\hat{y})+\frac{1}{2}h_i(\hat{y}_i-\hat{y})^2\right] $$ 4. 实现自定义损失函数自定义损失函数表示成$g_i$和$h_i$的形式后,我们可以将它们带入XGBoost的目标函数中,从而实现自定义损失函数。具体而言,我们需要重载XGBoost中的两个函数: * \_\_call\_\_(self, preds, labels) * create\_obj(self) 第一个函数用于计算预测值和真实值的损失函数值,第二个函数用于创建自定义的目标函数。在这两个函数中,我们需要根据自定义损失函数来计算$g_i$和$h_i$,并将它们传递给XGBoost的目标函数。 下面是一个简单的例子,展示了如何在XGBoost中实现自定义损失函数: ```python import xgboost as xgb import numpy as np # 定义自定义损失函数 def my_loss(y_true, y_pred): diff = y_true - y_pred grad = -2 * diff hess = 2 * np.ones_like(y_true) return grad, hess # 实现自定义的目标函数 class MyObjective(xgb.core.ObjFunction): def __call__(self, preds, labels): grad, hess = my_loss(labels, preds) return grad, hess def create_obj(self): return self # 模拟数据 X = np.random.normal(size=(100, 10)) y = np.random.normal(size=100) # 定义模型 params = { 'objective': MyObjective(), 'eval_metric': 'rmse', 'max_depth': 3, 'learning_rate': 0.1, 'n_estimators': 100 } model = xgb.XGBRegressor(**params) # 训练模型 model.fit(X, y) ``` 在上面的代码中,我们定义了一个自定义损失函数`my_loss`,它计算每个样本的一阶导数和二阶导数。然后,我们实现了一个自定义的目标函数`MyObjective`,它将自定义损失函数传递给XGBoost的目标函数。最后,我们使用这个自定义的目标函数来训练一个XGBoost回归模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值