我正在尝试使用自定义数据迭代器,如下所示
此处
,因为我的数据集太大。只是为了测试它是如何工作的,我正在使用示例的子集并运行以下代码。
X
是我的数据的 numpy 数组。
我的迭代器如下所示
class IterForQDMatrix(xgb.core.DataIter):
def __init__(self, df, batch_size):
self.df = df
self.batch_size = batch_size
self.batches = np.ceil(len(df) // self.batch_size)
self.it = 0
super().__init__()
def reset(self):
self.it = 0
def next(self, input_data):
if self.it == self.batches:
print("done")
return 0
a = self.it * self.batch_size
b = min((self.it + 1) * self.batch_size, len(self.df))
input_data(data=self.df[a:b, : -1], label=self.df[a:b, -1])
self.it += 1
return 1
iterator = IterForQDMatrix(X, 30)
xgb_data = xgb.QuantileDMatrix(iterator)
当我运行上面的代码时我注意到
"done"
被打印了四次,这意味着当我将迭代器传递给
xgb.QuantileDMatrix
时,它会遍历整个数据集四次。我试图理解为什么它要传递数据四次。有没有一种方法可以通过一次数据传递来实现它正在做的事情?
xgboost.QuantileDMatrix
对的数据进行四次传递来计算分位数草图,这些草图是有效训练树状模型所必需的。以下是原因:
- 初始化: 第一次传递用于收集有关数据集的基本统计信息,例如数据点的数量。此信息用于初始化分位数草图数据结构。
- 草图: 第二次和第三次传递用于构建分位数草图。这些草图是数据的汇总表示,允许 XGBoost 近似每个节点处特征值的分位数,而无需将所有数据存储在内存中。这对于大型数据集至关重要,因为它们无法完全加载到内存中。XGBoost 使用一种称为 GK-sketch 的方法来构建这些草图,该方法需要两次传递数据以有效地估计分位数。
- 最终确定: 第四次传递用于计算基于在草图构建阶段收集的信息的精确分位数。然后使用这些分位数来确定训练期间的拆分点。
可以只使用一次传递吗?
不,不能只使用一次传递来实现
xgboost.QuantileDMatrix
的功能,同时保持其效率。分位数草图的设计是为了在准确性和效率之间提供一个良好的平衡。它们允许 XGBoost 近似分位数,而无需多次遍历所有数据或将所有数据存储在内存中。
可以使用更少的传递吗?
从技术上讲,可以修改 XGBoost 的实现以在内部存储草图并重复使用它们。这将消除重复传递的需要。但是,此功能当前不可用。
替代方案
如果数据传递的数量成为一个主要问题,可以考虑以下替代方案:
- 对数据进行预处理以减少其大小: 这可以通过降维技术或特征选择来完成。
-
使用不同的 XGBoost 构造函数:
xgb.DMatrix
构造函数不需要计算分位数草图,并且可以在数据已经存储在内存中的情况下使用。但是,对于大型数据集,此方法可能不可行。 - 使用不同的梯度提升库: 一些梯度提升库,例如 LightGBM,使用不同的技术来处理大型数据集,并且可能需要更少的数据传递。
最终,选择最佳方法取决于的特定数据集和用例。
标签:python,machine-learning,parallel-processing,xgboost,quantile From: 76569411