xgboost内置了足够丰富的目标函数(objective function),正常来说是能够应付日常需求的,如果~万一~你有特殊需求,它也可以自定义目标函数,或者叫损失函数(loss function)
xgboost的documentation里有介绍如何自定义目标函数,https://xgboost.readthedocs.io/en/stable/tutorials/custom_metric_obj.html
Squared Log Error
按照文档中Squared Log Error (SLE),记录一下这个过程
Squared Log Error:
$$\frac{1}{2}\left [ \log (\hat{y} + 1) – \log (y + 1) \right ]^2$$
其中$y$是实际值,$\hat{y}$是预测值,$\log$里面加1是避免出现$\log(0)$的情况。我们可以直接用损失函数来评估模型的好坏,或者用metric来评估,比如下面这个,文档里叫它Root Mean Squared Log Error(RMSLE)
$$\sqrt{\frac{1}{N}\left [ \log (\hat{y} + 1) – \log (y + 1) \right ]^2}$$
函数实现
可以把我们自己写的目标函数丢给xgboost.train方法,这样训练过程中目标函数和metric就会按照我们自定义的进行fit。看一下documentation中xgboost.train的部分:

正如你想象的那样,obj参数接收的是自定义的目标函数,feval是自定义的metric,目标函数(obj)接收两个参数:一个是predt, np.ndarray格式的,表示前面$i-1$轮迭代后输出的预测值$\hat{y}$,可以标记为:
$$F_{i-1}(x) = \sum_{i-1}f_i(x)$$
其中$f_i$是基学习器。另一个dtrain, xgb.DMatrix格式的,装了一些训练集的信息,features并不会传送过来,因为太大了,并且计算object也用不上。需要返回两个np.ndarray的变量,一个是gradient, 另一个是hessian,即一阶和二阶导数。如果你看过上篇的内容,可能会有疑问为什么要用二阶导数?这个在后面的文章再介绍吧~
Gradient:
$$\frac{\partial \text{obj}}{\partial \hat{y}} = \frac{\log(\hat{y} + 1 – \log(y+1)}{\hat{y} + 1}$$
Hessian:
$$\frac{\partial ^2\text{obj}}{\partial \hat{y}^2} = \frac{1 + \log (\hat{y} + 1) – \log(y+1)}{(\hat{y} + 1)^2}$$
用Python实现上述两个公式:
def gradient(y_pred, y_true):
numerator = np.log(y_pred + 1) - np.log(y_true + 1)
denominator = y_pred + 1
return numerator / denominator
def hessian(y_pred, y_true):
numerator = 1 + np.log(y_true + 1) - np.log(y_pred + 1)
denominator = np.power(y_pred + 1, 2)
return numerator / denominator
按照API的要求实现obj函数:
def objective_function(pred, dtrain):
y_true = dtrain.get_label()
grad = gradient(pred, y_true)
hess = hessian(pred, y_true)
return grad, hess
顺便按照要求把metric也实现了:
def evaluate_function(pred, dtrain):
y_true = dtrain.get_label()
n = len(pred)
evaluate_name = 'rmsle'
evaluate_value = np.sqrt(np.mean(np.power(np.log(pred + 1) - np.log(y_true + 1), 2)))
return evaluate_name, evaluate_value
然后在train模型的时候像这样装填一下我们自定义的obj和feval
bst = xgb.train(param,
train_data,
num_boost_round=2,
evals=[(test_data, 'test')],
verbose_eval=True,
obj = objective_function,
feval = evaluate_function
)
大概就是这些了,xgboost只是个引子,后面我们展开聊一下LightGBM自定义目标函数的事。