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, ...)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.
- ...
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
train_data <- as.data.frame(as.matrix(agaricus.train$data))
train_data$label <- agaricus.train$label
dtrain <- xgboost::xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
set.seed(3691)
bst <- xgboost::xgb.train(
data = dtrain,
max_depth = 3,
nrounds = 3,
objective = "binary:logistic",
verbose = 0
)
# 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)
set.seed(9158)
bst_reg <- xgboost::xgb.train(
data = dtrain_reg,
max_depth = 3,
nrounds = 3,
objective = "reg:squarederror",
verbose = 0
)
party_tree_reg <- as.party(bst_reg, tree = 1L, data = reg_data)
print(party_tree_reg)
}
#> Warning: Passed invalid function arguments: max_depth. These should be passed as a list to argument 'params'. Conversion from argument to 'params' entry will be done automatically, but this behavior will become an error in a future version.
#> Warning: Argument 'objective' is only for custom objectives. For built-in objectives, pass the objective under 'params'. This warning will become an error in a future version.
#>
#> Model formula:
#> ~`odor=none` + `spore-print-color=green` + `stalk-root=club` +
#> `stalk-surface-below-ring=scaly` + `bruises?=bruises` + `stalk-root=rooted` +
#> `odor=foul`
#>
#> Fitted party:
#> [1] root
#> | [2] odor=none <= 2.00001
#> | | [3] spore-print-color=green <= 2.00001: 0.057 (n = 6513, err = 348.1)
#> | | [4] spore-print-color=green > 2.00001
#> | | | [5] stalk-surface-below-ring=scaly <= 2.00001: NA (n = 0, err = NA)
#> | | | [6] stalk-surface-below-ring=scaly > 2.00001: NA (n = 0, err = NA)
#> | [7] odor=none > 2.00001
#> | | [8] stalk-root=club <= 2.00001
#> | | | [9] bruises?=bruises <= 2.00001: NA (n = 0, err = NA)
#> | | | [10] bruises?=bruises > 2.00001: NA (n = 0, err = NA)
#> | | [11] stalk-root=club > 2.00001
#> | | | [12] stalk-root=rooted <= 2.00001: NA (n = 0, err = NA)
#> | | | [13] stalk-root=rooted > 2.00001: NA (n = 0, err = NA)
#>
#> Number of inner nodes: 6
#> Number of terminal nodes: 7
#> Warning: Passed invalid function arguments: max_depth. These should be passed as a list to argument 'params'. Conversion from argument to 'params' entry will be done automatically, but this behavior will become an error in a future version.
#> Warning: Argument 'objective' is only for custom objectives. For built-in objectives, pass the objective under 'params'. This warning will become an error in a future version.
#>
#> 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