单调约束
在模型问题或项目中,通常情况下可接受模型的函数形式在某种程度上受到限制。这可能是由于业务考虑,或是因为所研究的科学问题的类型。在某些情况下,如果对真实关系的某些特性有非常强烈的先验信念,可以使用约束来提高模型的预测性能。
在这种情况下,一种常见的约束类型是某些特征与预测响应之间存在**单调**关系:
每当 \(x \leq x'\) 是一个**递增约束**;或
每当 \(x \leq x'\) 是一个 递减约束。
XGBoost 具有在增强模型中使用的任何特征上强制执行单调性约束的能力。
一个简单的例子
为了说明,让我们根据以下方案创建一些带有两个特征和一个响应的模拟数据
响应通常随着 \(x_1\) 特征的增加而增加,但叠加了一个正弦变化,导致真实效果是非单调的。对于 \(x_2\) 特征,变化是递减的,并伴随一个正弦变化。
让我们在不施加任何单调约束的情况下,将提升树模型拟合到这些数据上:
黑色曲线显示了模型推断的每个特征的趋势。为了绘制这些图,将区分特征 \(x_i\) 输入到模型中,覆盖一维值网格,而所有其他特征(在这种情况下只有一个其他特征)设置为其平均值。我们看到模型很好地捕捉了叠加振荡波的总体趋势。
以下是相同的模型,但带有单调性约束:
我们看到约束的效果。对于每个变量,趋势的总体方向仍然明显,但振荡行为不再存在,因为它会违反我们施加的约束。
在XGBoost中强制单调约束
在XGBoost中强制单调性约束非常简单。这里我们将使用Python给出一个示例,但同样的通用思想也适用于其他平台。
假设以下代码适合您的模型,且不受单调性约束
model_no_constraints = xgb.train(params, dtrain,
num_boost_round = 1000, evals = evallist,
early_stopping_rounds = 10)
然后,仅使用单调性约束进行拟合只需要添加一个参数
params_constrained = params.copy()
params_constrained['monotone_constraints'] = (1,-1)
model_with_constraints = xgb.train(params_constrained, dtrain,
num_boost_round = 1000, evals = evallist,
early_stopping_rounds = 10)
在这个例子中,训练数据 X
有两列,通过使用参数值 (1,-1)
,我们告诉 XGBoost 对第一个预测器施加递增约束,对第二个预测器施加递减约束。
其他一些例子:
(1,0)
: 对第一个预测变量增加约束,对第二个预测变量无约束。(0,-1)
: 第一个预测器没有约束,第二个预测器有递减约束。
备注
关于 ‘hist’ 树构建算法的说明。如果 tree_method
设置为 hist
或 approx
,启用单调约束可能会产生不必要的浅树。这是因为 hist
方法减少了每次分割时考虑的候选分割数量。单调约束可能会消除所有可用的分割候选,在这种情况下不会进行分割。为了减少这种影响,您可能希望增加 max_bin
参数以考虑更多的分割候选。
使用功能名称
XGBoost 的 Python 包支持使用特征名称而不是特征索引来指定约束。给定一个包含列 ["f0", "f1", "f2"]
的数据框,单调约束可以指定为 {"f0": 1, "f2": -1}
,而 "f1"
将默认为 ``0``(无约束)。