Convert a single tree from an xgboost boosted tree model to a party object for use with partykit visualization and analysis tools.
Usage
# S3 method for class 'xgb.Booster'
as.party(obj, tree = 1L, data, nthread = NULL, ...)Arguments
- obj
An
xgb.Boosterobject from the xgboost package.- tree
Integer specifying which tree to convert (1-based indexing, default is 1). For multiclass models with
num_classclasses andnroundsboosting rounds, there arenum_class * nroundstotal trees.- data
data.frame containing the training data with the response variable included (required). XGBoost models do not store the original training data or response values. You must provide the original data frame that includes both the predictor variables and the response variable.
- nthread
Integer number of threads to use when reading the tree structure out of the model. The default (
NULL) inherits thenthreadthe booster was trained with.- ...
Not currently used.
Details
Important note on data
XGBoost models do not store the original training data or response values.
You must provide the original data frame (including the response variable)
via the data parameter for correct terminal node statistics, bar charts,
and other visualizations.
XGBoost tree storage format
xgboost stores trees in a tabular format accessible via
xgboost::xgb.model.dt.tree(). Each tree is represented as rows in a table:
Tree: 0-based tree index (e.g., 0, 1, 2, ...)Node: 0-based node ID within tree (e.g., "0-0", "0-1" for tree 0)Feature: Feature name (character) or "Leaf" for terminal nodesSplit: Numeric threshold for splits (NA for leaves)Yes: 0-based node ID of yes branch (feature < threshold)No: 0-based node ID of no branch (feature >= threshold)Missing: 0-based node ID for missing valuesQuality: Prediction value for leaf nodes, gain for internal nodes
Node indexing
Internally, xgboost uses 0-based tree and node indices
User-facing
treeparameter uses 1-based indexing (R convention)When
tree=1is requested, we filter toTree==0internally
Split encoding
Yes branch: feature < threshold (left child)
No branch: feature >= threshold (right child)
partykit split created with
right = TRUE(right interval closed)
Examples
if (rlang::is_installed("xgboost")) {
data(agaricus.train, package = "xgboost")
# Binary classification example, on a small subset for a fast example.
rows <- seq_len(200)
train_data <- as.data.frame(as.matrix(agaricus.train$data[rows, ]))
train_data$label <- agaricus.train$label[rows]
dtrain <- xgboost::xgb.DMatrix(
agaricus.train$data[rows, ],
label = agaricus.train$label[rows],
nthread = 1
)
set.seed(3691)
bst <- xgboost::xgb.train(
data = dtrain,
nrounds = 3,
verbose = 0,
params = xgboost::xgb.params(
max_depth = 3,
objective = "binary:logistic",
nthread = 1
)
)
# Convert first tree - data parameter is required
party_tree <- as.party(bst, tree = 1L, data = train_data)
print(party_tree)
plot(party_tree)
# Regression example
data(mtcars)
reg_data <- mtcars
dtrain_reg <- xgboost::xgb.DMatrix(
as.matrix(mtcars[, -1]),
label = mtcars$mpg,
nthread = 1
)
set.seed(9158)
bst_reg <- xgboost::xgb.train(
data = dtrain_reg,
nrounds = 3,
verbose = 0,
params = xgboost::xgb.params(
max_depth = 3,
objective = "reg:squarederror",
nthread = 1
)
)
party_tree_reg <- as.party(bst_reg, tree = 1L, data = reg_data)
print(party_tree_reg)
}
#>
#> Model formula:
#> ~`odor=pungent`
#>
#> Fitted party:
#> [1] root
#> | [2] odor=pungent <= 2.00001: 0.250 (n = 200, err = 37.5)
#> | [3] odor=pungent > 2.00001: NA (n = 0, err = NA)
#>
#> Number of inner nodes: 1
#> Number of terminal nodes: 2
#>
#> Model formula:
#> ~cyl + wt + hp + disp
#>
#> Fitted party:
#> [1] root
#> | [2] cyl <= 6
#> | | [3] wt <= 2.32: 30.067 (n = 6, err = 44.6)
#> | | [4] wt > 2.32
#> | | | [5] hp <= 97: 23.333 (n = 3, err = 1.7)
#> | | | [6] hp > 97: 21.450 (n = 2, err = 0.0)
#> | [7] cyl > 6
#> | | [8] cyl <= 8
#> | | | [9] wt <= 3.435: 20.775 (n = 4, err = 1.6)
#> | | | [10] wt > 3.435: 18.367 (n = 3, err = 1.1)
#> | | [11] cyl > 8
#> | | | [12] hp <= 205: 16.786 (n = 7, err = 16.6)
#> | | | [13] hp > 205: 13.414 (n = 7, err = 28.8)
#>
#> Number of inner nodes: 6
#> Number of terminal nodes: 7
