R语言xgboost模型预测结果与手动计算预期不符问题咨询
XGBoost单棵树预测结果与手动推导不一致问题
以下代码构建了一个简单的XGBoost模型,用于复现遇到的问题。模型训练完成后,调用模型执行预测并取数据集的第二行结果。对第10轮和第9轮模型预测值的相对差异取对数,所得结果应为第10棵树的预测值,本案例中该值为0.00873184。
现在将树的输入(矩阵a的第2行取值为0.1234561702)代入模型手动推导,预期预测值应为0.0121501638。但实际运行时发现,第二次分裂(阈值<0.123456173)后节点走向错误,最终得到的节点值为0.00873187464,仅与预期值接近。
请问该问题的成因是什么?
依赖版本
- R: 4.1.0
- xgboost: 1.4.1.1
- dplyr: 1.0.7
- data.table: 1.14.0
复现代码
library(xgboost) library(dplyr) library(data.table) set.seed(2) a <- matrix(runif(1000,0.1234561,0.1234562), ncol=1,nrow=1000) colnames(a) <- c("b") d <- abs(rnorm(1000,3*a[,1])) d2 <- xgb.DMatrix(data = a,label = d) e <- xgboost::xgboost(data=d2,nrounds=10,method="hist",objective="reg:gamma") xgb.plot.tree(e$feature_names,e,trees=9) x <- 2 log((predict(e,a,ntreelimit = 10)/predict(e,a,ntreelimit = 9)))[x] format(a[x,],nsmall=10)
问题原因
核心成因是浮点数精度误差和直方图算法的分桶逻辑:
- 你使用的
method="hist"训练模式会先对连续特征做分桶处理,为了提升计算效率,分桶过程会对特征值做精度截断。你用到的特征值0.1234561702和分裂阈值的差值极小,已经接近双精度浮点数的有效精度边界,分桶时会被判定到同一桶内,最终导致节点走向和手动推导结果不一致。 - 树可视化时展示的分裂阈值是做了四舍五入的展示值,模型实际存储的阈值和你手动推导时用到的显示值存在微小差异,也是判断误差的来源之一。
reg:gamma目标函数的预测值是经过对数空间转换得到的,转换过程本身也会引入微小的浮点计算误差,最终累加导致结果和预期值存在偏差。
如果需要完全匹配手动推导结果,可以将训练参数替换为method="exact",Exact贪心算法不会做特征分桶,会逐一遍历所有特征的原始分裂点,不会出现精度截断导致的节点走偏问题。
内容的提问来源于stack exchange,提问作者user16026181
相关产品推荐
相关产品推荐

