索引化元素的处理
XGBoost 中有许多功能引用了可数集合中的索引化元素,例如模型中的提升轮次 / 迭代 / 树(可以通过数字引用)、类别、分类特征中的类别 / 层级等。
XGBoost 使用 C++ 编写,因此使用基于 0 的索引,并且范围/序列包含左端但不包含右端——例如,范围 (0, 3) 将包含前三个元素,编号为 0、1 和 2。
Python 接口使用相同的逻辑,因为这也是 Python 中索引的工作方式,但像 R 这样的其他语言则有不同的逻辑。在 R 中,索引是基于 1 的,并且范围/序列包含两端——例如,要引用序列中的前三个元素,区间将写为 (1, 3),元素编号为 1、2 和 3。
为了提供更符合 R 习惯的接口,XGBoost 调整了其面向用户的 R 接口以遵循此约定及类似的 R 约定,但在内部,它需要将所有这些数字转换为 C 接口使用的格式。模型的序列化和在具有不同索引逻辑的其他接口中加载的事实使得这个问题更加复杂。
在 R 接口中进行了以下调整
DMatrix 的切片方法接受一个整数数组,通过从每个元素中减去 1 将其转换为基于 0 的索引。请注意,这是在 R 的 C 级包装函数中完成的,与其他所有在传递给 C 之前在 R 中完成的转换不同。
Booster 的切片方法接受由 start、end 和 step 定义的序列。从用户的角度来看,R 接口的工作方式与 R 的
seq
相同,因此它总是通过减一调整左端,并且取决于步长是否恰好或不恰好在右端结束,也会调整右端使其在 C 索引中不包含。predict
中的参数iterationrange
也被设计为与 R 的seq
行为相同。由于它没有步长,只需将左端减去 1 就足够了。best_iteration
根据上下文,可能既存储为 C 级 booster 属性,也存储为 R 属性。由于 C 级属性在不同接口之间共享并用于预测方法,为了提高兼容性,它将此 C 级属性保留为基于 0 的索引,但如果存在 R 属性,则会调整为基于 1 的索引。请注意,R 和其他接口中的predict
方法只会查看 C 级属性。其他对迭代次数或提升轮次的引用,例如在打印度量或保存模型快照时,也遵循基于 1 的索引。这些其他引用完全在 R 中编写代码,因为 C 级函数不处理此类功能。
末端叶子/节点编号以基于 0 的索引返回,就像它们来自 C 接口一样。
图中的树编号遵循基于 1 的索引。请注意,这些只在使用 R 接口自身处理 DiagrammeR 对象生成这些图时显示,而不在使用 C 级的 GraphViz 'dot' 格式生成器生成图时显示。
在生成特征重要性、JSON、trees-to-tables 和 SHAP 时,特征编号都遵循基于 0 的索引。
分类特征在 R 中定义为
factor
类型,它使用基于 1 的索引进行编码。当分类特征作为 Rfactor
类型传递时,会自动转换为基于 0 的索引,但如果用户希望手动提供已编码的整数作为分类特征,则这些整数需要已经是基于 0 的编码。在图、JSON 和 trees-to-tables 等输出中,分类级别(类别)也使用基于 0 的索引引用,无论它们是以整数形式还是
factor
类型列的形式进入模型。DMatrices 的分类标签不进行任何额外处理 - 用户必须提供基于 0 编码的标签。
在使用线性系数历史回调函数时,用于检索特定类别系数的函数接受一个类别索引参数,该参数也不进行任何转换(即用户必须传递基于 0 的索引),以便与标签逻辑匹配——也就是说,相同的类别索引将引用 DMatrix
label
字段中使用该数字编码的类别。
R 接口中接受索引化元素的新增功能应注意这些约定,并尽可能模仿 R 的行为。