特征交互约束

决策树是发现自变量(特征)之间交互的强大工具。遍历路径中一起出现的变量相互作用,因为子节点的条件取决于父节点的条件。例如,下图中突出显示的红色路径包含三个变量:\(x_1\)\(x_7\)\(x_{10}\),因此突出显示的预测(在突出显示的叶节点处)是 \(x_1\)\(x_7\)\(x_{10}\) 之间交互作用的结果。

../_images/feature_interaction_illustration1.svg

当树的深度大于一时,许多变量仅基于最小化训练损失而相互作用,生成的决策树可能捕获的是虚假关系(噪声),而不是能泛化到不同数据集的合法关系。特征交互约束允许用户决定哪些变量可以交互,哪些变量不能。

潜在的好处包括

  • 通过关注有效的交互作用来获得更好的预测性能——无论是通过领域特定知识还是通过对交互作用进行排序的算法

  • 预测中的噪声更少;更好的泛化能力

  • 用户对模型能拟合的内容有更多控制。例如,即使某些交互作用表现良好,用户可能由于监管限制而希望将其排除在外。

一个简单示例

特征交互约束表示为一组允许相互作用的变量。例如,约束 [0, 1] 表示变量 \(x_0\)\(x_1\) 允许相互作用,但不能与任何其他变量作用。同样,[2, 3, 4] 表示 \(x_2\)\(x_3\)\(x_4\) 允许相互作用,但不能与任何其他变量作用。一组特征交互约束表示为一个嵌套列表,例如 [[0, 1], [2, 3, 4]],其中每个内部列表是一组允许相互作用的特征索引。

在下图中,左边的决策树违反了第一个约束 ([0, 1]),而右边的决策树符合第一个和第二个约束 ([0, 1], [2, 3, 4])。

fig1

fig2

禁止的

允许的

在 XGBoost 中强制执行特征交互约束

在 XGBoost 中强制执行特征交互约束非常简单。这里我们将提供一个使用 Python 的示例,但相同的通用思想也适用于其他平台。

假设以下代码在没有特征交互约束的情况下拟合你的模型

model_no_constraints = xgb.train(params, dtrain,
                                 num_boost_round = 1000, evals = evallist,
                                 early_stopping_rounds = 10)

然后,使用特征交互约束进行拟合只需要添加一个参数

params_constrained = params.copy()
# Use nested list to define feature interaction constraints
params_constrained['interaction_constraints'] = '[[0, 2], [1, 3, 4], [5, 6]]'
# Features 0 and 2 are allowed to interact with each other but with no other feature
# Features 1, 3, 4 are allowed to interact with one another but with no other feature
# Features 5 and 6 are allowed to interact with each other but with no other feature

model_with_constraints = xgb.train(params_constrained, dtrain,
                                   num_boost_round = 1000, evals = evallist,
                                   early_stopping_rounds = 10)

使用特征名称代替

XGBoost 的 Python 和 R 包支持使用特征名称而不是特征索引来指定约束。给定一个列为 ["f0", "f1", "f2"] 的数据框,特征交互约束可以指定为 [["f0", "f2"]] (Python) 或 list(c("f0", "f2")) (R,当将它们传递给函数 xgboost() 时)。

进阶主题

交互约束的直观理解很简单。用户可能对不同特征之间的关系有先验知识,并在模型构建过程中将其编码为约束。但在指定约束时也有一些微妙之处。以约束 [[1, 2], [2, 3, 4]] 为例。第二个特征出现在两个不同的交互集合中,[1, 2][2, 3, 4]。因此,允许与 2 交互的特征的并集是 {1, 3, 4}。在下图中,根节点在特征 2 处进行分裂。因为其所有后代都应该能够与其交互,所以在第二层,所有 4 个特征都是合法的分裂候选者。乍一看,这可能像是忽略了指定的约束集,但事实并非如此。

../_images/feature_interaction_illustration4.png

{1, 2, 3, 4} 代表合法的分裂特征集合。

这带来了一些有趣的特征交互约束的含义。再以 [[0, 1], [0, 1, 2], [1, 2]] 为例。假设为了演示方便,我们的训练数据集中只有 3 个可用特征,细心的读者可能会发现上述约束与简单的 [[0, 1, 2]] 是一样的。因为无论在根节点选择哪个特征进行分裂,其所有后代都允许将每个特征作为合法分裂候选者,而不会违反交互约束。

最后一个例子,我们使用 [[0, 1], [1, 3, 4]] 并选择特征 0 作为根节点的分裂特征。在构建树的第二层,除了特征 0 本身之外,1 是唯一合法的分裂候选者,因为它们属于同一个约束集。沿着下面示例树的生长路径,第二层的节点在特征 1 处分裂。但由于 1 也属于第二个约束集 [1, 3, 4],所以在第三层,我们允许将所有特征都包括作为分裂候选者,并且仍然符合其祖先节点的交互约束。

../_images/feature_interaction_illustration6.png

{0, 1, 3, 4} 代表合法的分裂特征集合。