dtreeviz 有一种简单且相当直观的方式来可视化决策树。当我们使用 XGBoost 模型进行训练时,通常会创建许多树。测试数据的预测将涉及所有树的值的累积相加,以得出测试目标值。我们如何从这些树中可视化出具有代表性的树?
在尝试回答这个问题时,我使用了 sklearn 加州住房数据并使用 XGBoost 进行了训练。这是代码:
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
import xgboost as xgb
housing = fetch_california_housing()
X_train, X_valid, y_train, y_valid = train_test_split(housing.data, housing.target,
test_size = 0.33, random_state = 11)
dtrain = xgb.DMatrix(data=X_train, label=y_train)
dvalid= xgb.DMatrix(data=X_valid, label=y_valid)
# specify xgboost parameters and train the model
params_reg = {"max_depth":4, "eta":0.3, "objective":"reg:squarederror", "subsample":1}
xgb_model_reg = xgb.train(params=params_reg, dtrain=dtrain, num_boost_round=1000, \
early_stopping_rounds=50, evals=[(dtrain, "train"),(dvalid, "valid")], verbose_eval=True)
当我使用
early_stopping_rounds
时,它在以下迭代处停止:
[0] train-rmse:1.46031 valid-rmse:1.47189
[1] train-rmse:1.14333 valid-rmse:1.15873
[2] train-rmse:0.93840 valid-rmse:0.95947
[3] train-rmse:0.80224 valid-rmse:0.82699
...
[308] train-rmse:0.28237 valid-rmse:0.47431
[309] train-rmse:0.28231 valid-rmse:0.47429
xgb_model_reg.best_iteration
是 260。
使用这棵最好的树,我绘制了一个 dtreeviz 树,如下所示:
from dtreeviz import trees
from dtreeviz.models.xgb_decision_tree import ShadowXGBDTree
best_tree = xgb_model_reg.best_iteration
xgb_shadow_reg = ShadowXGBDTree(xgb_model_reg, best_tree, housing.data, housing.target, \
housing.feature_names, housing.target_names)
trees.dtreeviz(xgb_shadow_reg)
如果我使用此
ShadowXGBDTree
为验证行绘制通过此树的预测路径,它会返回与模型预测的值不同的值。为了便于说明,我随机选择了X_valid[50]
并绘制了它的预测路径,如下所示:
# predict
y_pred = xgb_model_reg.predict(dvalid)
# select a sample row and visualize path
X_sample = X_valid[50]
viz = trees.dtreeviz(xgb_shadow_reg,
X_valid,
y_valid,
target_name='MedHouseVal',
orientation ='LR', # left-right orientation
feature_names=housing.feature_names,
class_names=list(housing.target_names),
X=X_sample)
viz
但是,
y_valid[50]
是 1.741,甚至 y_pred[50]
是 1.5196749,两者都不符合图中所示的值。我想这是预料之中的,因为我只使用这个特定的树进行路径预测。那么应该如何选择代表性树呢?
有什么想法可以最好地解决这个问题吗?谢谢你。
在探索这个问题几个月后,我决定以我选择的前进方向来回应,因为其他人似乎也处于类似的情况。我提出这个问题的主要目的是弄清楚是否有办法解释 XGBoost 模型的预测。然而,由于 XGBoost 的理论上定义方式,获得单个代表性决策树看起来并不可行。相反,我决定执行SHAP分析来解释其预测。
继续问题中给出的代码,以下是执行 SHAP 分析的代码要点:
import shap
# Create a tree explainer
xgb_explainer = shap.TreeExplainer(
xgb_model_reg, X_train, feature_names=list(housing.feature_names)
)
data_dmatrix = xgb.DMatrix(data=X_valid,label=y_valid)
y_pred = xgb_model_reg.predict(data_dmatrix)
shap_explainer_values = xgb_explainer(X_valid, y_pred)
为了说明,如果我们想解释为什么 y_pred[50] 有 1.5196749,例如,我们可以用这一行生成瀑布图:
shap.waterfall_plot(shap_explainer_values[50])
这是生成的瀑布图:
从该图中,特征经度和纬度对相反方向的预测影响最大。房屋的纬度比批次基值
E[f(x)]
正增加了2,但其经度使该值下降了-2.19。这种表示很容易有助于解释模型预测。