XGBoost单树预测组合与model.predict()结果不符,如何修正?
尝试提取XGBoost中每棵树的预测结果并组合,验证是否与model.predict()输出一致,但组合结果完全不匹配。计划导出模型到其他平台实现预测,先在Python中验证逻辑,现有代码及报错如下:
import numpy as np import xgboost as xgb from sklearn import datasets from scipy.special import expit as sigmoid, logit as inverse_sigmoid # Load data iris = datasets.load_iris() X, y = iris.data, (iris.target == 1).astype(int) # Fit a model model = xgb.XGBClassifier( n_estimators=10, max_depth=10, use_label_encoder=False, objective='binary:logistic' ) model.fit(X, y) booster_ = model.get_booster() # Extract indivudual predictions individual_preds = [] for tree_ in booster_: individual_preds.append( tree_.predict(xgb.DMatrix(X)) ) individual_preds = np.vstack(individual_preds) # Aggregated individual predictions to final predictions indivudual_logits = inverse_sigmoid(individual_preds) final_logits = indivudual_logits.sum(axis=0) final_preds = sigmoid(final_logits) # Verify correctness xgb_preds = booster_.predict(xgb.DMatrix(X)) np.testing.assert_almost_equal(final_preds, xgb_preds)
报错信息:
AssertionError: Arrays are not almost equal to 7 decimals
Mismatched elements: 150 / 150 (100%)
Max absolute difference: 0.90511334
Max relative difference: 0.99744916
x: array([7.4847587e-05, 7.4847587e-05, 7.4847587e-05, 7.4847587e-05,
7.4847587e-05, 7.4847587e-05, 7.4847587e-05, 7.4847587e-05,
7.4847587e-05, 7.4847587e-05, 7.4847587e-05, 7.4847587e-05,...
y: array([0.0293127, 0.0293127, 0.0293127, 0.0293127, 0.0293127, 0.0293127,
0.0293127, 0.0293127, 0.0293127, 0.0293127, 0.0293127, 0.0293127,
0.0293127, 0.0293127, 0.0293127, 0.0293127, 0.0293127, 0.0293127,...
你忽略了两个核心细节:
- 单个树的输出是logit增量,而非概率:XGBoost中每棵决策树输出的是logit空间的累加值,不是经过sigmoid转换后的概率。你的代码错误地对单个树的结果做了
inverse_sigmoid转换,完全颠倒了逻辑。 - 遗漏了初始偏置(Base Score):XGBoost的最终预测是所有树的logit增量之和,加上初始base_score对应的logit值。默认base_score为0.5(对应logit为0),但训练时可能会调整,需要从模型中读取实际值。
修正后的验证代码:
import numpy as np import xgboost as xgb from sklearn import datasets from scipy.special import expit as sigmoid # Load data iris = datasets.load_iris() X, y = iris.data, (iris.target == 1).astype(int) # Fit a model model = xgb.XGBClassifier( n_estimators=10, max_depth=10, use_label_encoder=False, objective='binary:logistic' ) model.fit(X, y) booster_ = model.get_booster() # 提取每棵树的logit增量 individual_logits = [] for tree_ in booster_: individual_logits.append(tree_.predict(xgb.DMatrix(X))) individual_logits = np.vstack(individual_logits) # 获取base_score并转换为logit值 base_score = booster_.attributes().get('base_score', '0.5') base_logit = np.log(float(base_score) / (1 - float(base_score))) # 聚合得到最终预测 final_logits = individual_logits.sum(axis=0) + base_logit final_preds = sigmoid(final_logits) # 验证一致性 xgb_preds = booster_.predict(xgb.DMatrix(X)) np.testing.assert_almost_equal(final_preds, xgb_preds) # 此时断言会通过
修正后的逻辑完全对齐XGBoost原生预测流程:累加所有树的logit增量,加上初始偏置的logit值,最后通过sigmoid转换为概率。
内容的提问来源于stack exchange,提问作者rriccilopes

