Xgboost-如何使用"mae"作为目标函数?

Sam*_*ian 19 machine-learning xgboost

我知道xgboost需要第一个渐变和第二个渐变,但是其他人都使用"mae"作为obj函数吗?

Lit*_*les 37

先说一点理论,对不起!你要求MAE的grad和hessian,然而,MAE不是连续两次可微分,所以试图计算第一和第二衍生物变得棘手.下面我们可以看到"扭结" x=0,阻止MAE连续可微分.

此外,二阶导数在其表现良好的所有点处都为零.在XGBoost中,二阶导数用作叶子权重的分母,当为零时,会产生严重的数学错误.

鉴于这些复杂性,我们最好的办法是尝试使用其他一些表现良好的函数来近似MAE.让我们来看看.

一些不同的损失函数

我们可以看到上面有几个函数接近绝对值.显然,对于非常小的值,平方误差(MSE)是MAE的相当好的近似值.但是,我认为这对您的用例来说还不够.

胡贝尔损失是一个记录良好的损失函数.然而,它并不顺利,所以我们不能保证平滑的衍生品.我们可以使用Psuedo-Huber函数来近似它.它可以在python XGBoost中实现,如下所示,

import xgboost as xgb

dtrain = xgb.DMatrix(x_train, label=y_train)
dtest = xgb.DMatrix(x_test, label=y_test)

param = {'max_depth': 5}
num_round = 10

def huber_approx_obj(preds, dtrain):
    d = preds - dtrain.get_labels() #remove .get_labels() for sklearn
    h = 1  #h is delta in the graphic
    scale = 1 + (d / h) ** 2
    scale_sqrt = np.sqrt(scale)
    grad = d / scale_sqrt
    hess = 1 / scale / scale_sqrt
    return grad, hess

bst = xgb.train(param, dtrain, num_round, obj=huber_approx_obj)  
Run Code Online (Sandbox Code Playgroud)

替换它可以使用其他功能obj=huber_approx_obj.

公平损失根本没有完全记录,但似乎工作得相当好.公平损失函数是:

公平损失函数

它可以这样实现,

def fair_obj(preds, dtrain):
    """y = c * abs(x) - c**2 * np.log(abs(x)/c + 1)"""
    x = preds - dtrain.get_labels()
    c = 1
    den = abs(x) + c
    grad = c*x / den
    hess = c*c / den ** 2
    return grad, hess
Run Code Online (Sandbox Code Playgroud)

此代码是从Kaggle Allstate Challenge中的第二位解决方案中获取和改编的.

Log-Cosh Loss功能.

def log_cosh_obj(preds, dtrain):
    x = preds - dtrain.get_labels()
    grad = np.tanh(x)
    hess = 1 / np.cosh(x)**2
    return grad, hess
Run Code Online (Sandbox Code Playgroud)

最后,您可以使用上述功能作为模板创建自己的自定义损失函数.

  • 非常感谢乔什!快速评论log-cosh代码; `np.cosh`可以溢出一些输入,使用标识`hess = 1- np.tanh(x)**2`将避免这些问题. (2认同)
  • 我认为对于sklearn,您应该反转传递给目标函数的参数...第一个应该是标签,第二个应该是预测...在这种情况下,我想这并没有多大区别,但也会造成混乱。 get_labels-> get_label (2认同)