xgboost被誉为各大数据竞赛中的“重型武器”,好的效果,并行计算的速度都是其显著的优势。xgboost参数中默认的目标函数有限,很多情况下,需要根据任务自定义目标函数。关于如何在代码中定义目标函数,可以参考:https://github.com/dmlc/xgboost/blob/master/demo/guide-python/custom_objective.py
xgboost需要目标函数的二阶导数信息(或者hess矩阵),在回归问题中经常将MAE或MAPE作为目标函数,然而看两者的计算公式就可以知道:这两个目标函数二阶导数不存在。
式中,
解决这个问题的高质量解答很少,xgboost 使用 MAE或MAPE 作为目标函数这个博客以及里面给出的链接回答都比较模糊,下面是我对于这个问题的解决方法。
解决这个问题的两个主流方法:
1.利用可导的函数逼近MAE或者MAPE,这种方法更符合严谨的逻辑,所以后面重点阐述
2.直接自己定义一个二阶导数的值,比如直接将
利用MSE进行逼近是最简单的一种方法,但是MSE在训练初始误差较大的时候,loss是其平方,会使得训练偏离MAE的目标函数,一般难以达到高精度的要求。
利用Huber loss(Huber loss - Wikipedia)进行逼近,是更好的办法。其定义如下所示:
图1 是利用Hber loss逼近MAE的示意图,
但是值得注意的是Huber loss仍然不可导,实际又利用了Huber loss的可导逼近形式:Pseudo-Huber loss function作为目标函数(很多文章中没有讲清这一点),其定义为:
一阶导数为:
二阶导数为:
在
def
代码中的h就是公式中的
图2及图3分别是以Pseudo-Huber loss function和MAE loss作为逼近函数在同一个任务上,validation集上的实验结果(实验中
由上两图可以看出:Pseudo-Huber loss function逼近下的误差更小,收敛速度更快!
还可以用ln(cosh(x))以及 log(exp(-x) + exp(x))进行逼近,可以看一下几者的函数曲线
ln(cosh(x))的一阶导数:
tanh(x)
ln(cosh(x))的二阶导数:
1-tanh(x)*tanh(x)
ln(cosh(x))的代码:
def
可以对比一下ln(cosh(x))的Pseudo-Huber loss function的一阶,二阶导数图像:
可以看出,两者的一阶、二阶导数非常像!
在实践中选择适合自己问题的逼近函数形式吧!
对于MAPE的处理情况,就很简单了,将逼近函数的一阶和二阶导数除以