Skip to contents

R package version

lint

Status

Pre-1.0 and under active development. What exists today:

Figure Status
Boosting error path, with the optimal iteration marked Implemented
rho / phi / lambda parameter paths Implemented
Subject trajectories, observed against fitted Implemented
Variable importance Implemented
Partial and marginal effects Implemented
Calibration over follow-up, observed against fitted, with the cohort mean curve Implemented
BoostMLR as a second backend Partial — all six figures accept a BoostMLR fit, with partial effects through boostmlr_partial(); marginal effects and joint importance are not supported

The six implemented figures are complete and tested. The API for what exists is not expected to change; the list above is what is missing, not what is provisional.

ggBoostedTrees draws diagnostic figures for boosted tree models fit with boostmtree, which implements Friedman’s gradient descent boosting with multivariate tree base learners for longitudinal responses, with partial support for BoostMLR fits (see the status table above). It is the boosting counterpart to ggRandomForests, and follows the same two-step idiom: an extractor pulls a tidy data frame out of a fitted model, and autoplot() renders it. If you have a boostmtree fit and want to know whether it converged, this is the package. All six figures also accept a BoostMLR fit, within the limits in the status table.

The full reference — every function and the changelog — is online at https://ehrlinger.github.io/ggBoostedTrees/.

Installation

ggBoostedTrees is part of the HVTI R family. Install it with the rest of the family through hvtiR:

# install.packages("pak")
pak::pak("ehrlinger/hvtiR")
hvtiR::install()

hvtiR::install() installs every member in one call, so the versions the members require of one another resolve together. Update later with hvtiR::update(), from a fresh R session: it will not overwrite a package that is already loaded.

To install ggBoostedTrees on its own:

pak::pak("ehrlinger/ggBoostedTrees")

ggBoostedTrees requires a patched build of boostmtree, not the CRAN release. CRAN’s boostmtree 2.0.0 has three defects that reach these figures: frozen residuals under cv.flag = TRUE (which is exactly the flag the error path depends on), incorrect na.action handling, and malformed dimnames from vimp(joint = TRUE). The fixes live in a fork pending upstream merge.

That requirement is enforced rather than documented: the Imports floor is boostmtree (>= 2.0.1), and CRAN’s 2.0.0 cannot satisfy it. An install against the defective backend fails to resolve instead of silently producing wrong figures.

The Remotes: field points at the fork, so either command above installs the correct boostmtree for you. To install the backend on its own:

pak::pak("ehrlinger/boostmtree_src/boostmtree@v2.0.8-ccf")

Quick Start

Fit a model with cv.flag = TRUE, then ask whether it converged:

library(ggBoostedTrees)

set.seed(7)
sim <- boostmtree::simLong(n = 25, n.time = 4, model = 1)$data.list
fit <- boostmtree::boostmtree(
  x = sim$features, tm = sim$time, id = sim$id, y = sim$y,
  M = 50, cv.flag = TRUE, verbose = FALSE,
  control = boostmtree::boostmtree.control(seed = 7)
)

# The error path, with the cross-validated optimal iteration marked.
autoplot(fit)

cv.flag = TRUE is not optional for the error path. boostmtree records err.rate and m.opt only when cross-validation ran, so a default fit has no error path to draw and gg_boost_error() will say so.

It is also where the time goes. Cross-validation refits each step once for every subject left out of the tree, so its cost grows with the square of the number of subjects. Profiled on a laptop with simulated data of about 9 visits per subject, a 50-step fit on boostmtree 2.0.3 took 2.9 s at 75 subjects, 29 s at 300 and 108 s at 600, about 9 times the cost of the same fit without it at 300. boostmtree 2.0.4 runs those refits in parallel through boostmtree.control(cv.cores = ), and the fit is identical on any number of cores; at 600 subjects, 4 laptop cores took 33 s. Windows cannot fork and uses one core.

On a shared server the limit is memory, not speed. Each core is a forked copy of R, and about 80% of the fit runs in parallel, so speed levels off near 4 to 5 times however many cores it has. Measured on our server (boostmtree 2.0.4, an ordinal response, 10 steps), with peak memory at those 10 steps:

subjects 1 core 4 cores 8 cores
1,000 654 s, 1 GB 263 s, 5 GB 184 s, 11 GB
2,000 2,552 s, 3 GB 1,006 s, 19 GB 790 s, 30 GB
4,000 11,003 s, 13 GB 3,987 s, 69 GB ran out of memory

Time grows in proportion to the number of steps: at 4,000 subjects and 1,000 steps, the fit takes between four and five days on 4 cores. Memory grows with the steps too, because the fit keeps every one, about 0.35 MB per step per 1,000 visits for an ordinal response. The figures above are upper bounds at 10 steps only; at 1,000 steps add about 11 GB at 4,000 subjects for the fit itself, and possibly more for each core, which has not been measured.

Every figure is available as data as well as a plot, because the tidy frame is the point rather than an implementation detail:

gg_dta <- gg_boost_error(fit)
head(gg_dta, 3)
#>   iteration     value response optimal
#> 1         1 1.0118738        y   FALSE
#> 2         2 1.0008788        y   FALSE
#> 3         3 0.9912097        y   FALSE

# Returns a bare ggplot, so it composes with any theme or scale.
autoplot(gg_dta) + ggplot2::theme_bw()

The variance and smoothing parameter paths diagnose whether the variance structure settled before boosting stopped. They are always faceted on a free y scale, because rho, phi and lambda span three orders of magnitude:

autoplot(gg_boost_path(fit))

The trajectory plot is the one longitudinal boosting exists for — whether the model tracks individual subjects, not just the population mean:

autoplot(gg_boost_trajectory(fit))

Function reference

Figure data

Function Description
gg_boost_error() Boosting error path by iteration, with the cross-validated optimal iteration flagged. Requires cv.flag = TRUE.
gg_boost_path() Estimated rho, phi and lambda by iteration. Available on any fit.
gg_boost_trajectory() Observed and fitted subject trajectories over time, sorted within subject.
gg_boost_calibration() Observed and fitted values over follow-up, summarized in equal-count time bins with observed confidence intervals.
gg_boost_vimp() Variable importance for the main effect and the time interaction.
gg_boost_effect() Partial and marginal covariate effects over time, for both continuous and discrete (factor) covariates, and per response for ordinal, nominal and BoostMLR fits.
boostmlr_partial() Computes BoostMLR partial effects for one or more covariates, in the form gg_boost_effect() accepts.

Rendering

Function Description
autoplot.gg_boost_error() Error path as a line, with a dashed rule at the optimal iteration.
autoplot.gg_boost_path() Parameter paths, faceted by parameter on a free y scale.
autoplot.gg_boost_trajectory() Fitted trajectories as lines and observed values as points, thinned by subset/n_max with transparency scaled to cohort size.
autoplot.gg_boost_calibration() Observed and fitted bin means with observed confidence intervals and each bin’s time span.
autoplot.boostmtree() Shortcut from a fitted model straight to the error plot.
autoplot.gg_boost_vimp() Ordered horizontal bars, faceted by component.
autoplot.gg_boost_effect() Effect curves coloured by time, faceted by variable and, for several responses, by response.

plot() is an alias for autoplot() on every gg_boost_* object.

Documentation

  • Overview, vignette("ggBoostedTrees"), fits one small simulated model and walks it through every figure, from the error path to partial effects, then finishes a plot with +.