figsr (development version)
New features
-
ggfigs()draws a fitted model with ‘ggplot2’, in five views:"tree"(node-link diagram of every tree),"rules"(every tree as a horizontal rule list, with+between trees),"waterfall"(where the prediction for one observation comes from),"cuts"(the numeric cutpoints drawn over the data) and"profile"(exact partial dependence). It returns aggplot; withinteractive = TRUEit returns a ‘ggiraph’ widget whose tooltips show the rule behind each node, leaf or cut. ‘ggiraph’ is only suggested.autoplot()gives the sameggplots.
Bug fixes
-
plot()no longer draws boxes on top of each other. Nodes used to sit on a fixed grid, so in deeper trees neighboring leaves and branch conditions overlapped and their labels were cut off. Each split now places its subtrees from the width of their labels, every tree gets a panel width proportional to the room it needs, and all trees share one vertical scale, so their roots line up. A drawing too large for its panel is scaled down, text included, instead of clipped.
Performance
- The split search was rewritten and fitting is about 25 to 60 times faster (for example, 12.6 s to 0.33 s with 32,000 rows, 10 numeric predictors and
max_splits = 10), allocating about 30 times less memory. Everything that depends on the predictors alone (row order, cutpoints, level groups) is computed once per node instead of once per iteration, every cutpoint of a predictor is scored from a single cumulative sum of the residuals instead of one pass per cutpoint, and a leaf whose residuals did not change since the last iteration keeps its previous best split. The fitted model is unchanged: the same splits, cutpoints, missing-value directions and sample indices as 0.2.0, which a new regression test checks on fourteen data sets.
figsr 0.2.0
Documentation
- A new vignette,
vignette("missing-values"), works throughna_method = "mia"on the real Pima Indians Diabetes Database, where missingness is informative but modest, and showsplot()’s newmain,tree_namesand sign-colored leaves on it.
New data
-
pima_diabetes: the Pima Indians Diabetes Database (Smith et al. 1988), 768 patients, ships lazily loaded likeiris. Its five physiologically impossible zeros (Glucose,BloodPressure,SkinThickness,Insulin,BMI) are already recoded toNA, so it is ready to demonstratena_method = "mia"without an internet connection or preprocessing.
New features
plot()gainedmain, an overall title drawn once above every tree panel, andtree_names, overriding the automatic per-tree panel titles (a single string applies to every tree; a vector is indexed by each tree’s position in the fit, so it stays correct whentree_idxonly plots some of them;NAin a position keeps that tree’s default title). In the"scientific"and"modern"styles, a leaf’s background, border and text now depend on the sign of its contribution – green for positive, red for negative;"classic"stays monochromatic by design.figs(),fit_figs()andbagging_figs()gainedna_method. The default"omit"is the previous behavior."mia"(missingness incorporated in attributes, Twala et al. 2008) keeps every row: at each split the search also tries sending missing values left or right of the cutpoint, and splitting on missingness itself, and uses the learned direction at prediction time.summary()prints these asIS MISSINGclauses,plot()labels the edge missing values take, andfigsr_importance()reports a split on missingness on its ownmissing(<predictor>)row.
Bug fixes
- The
parsnipengine now fits through the formula interface. The previous data.frame interface ranmodel.frame()withna.omitbefore the engine, sofit()silently dropped rows with a missing predictor.
figsr 0.1.1
CRAN release: 2026-08-31
Bug fixes
figs()now carries the parent leaf’s value into the two leaves created by splitting it. Predictions from any tree deeper than one split were wrong before this fix.Classification probabilities are no longer passed through a logistic function. The engine fits squared error on the 0/1 encoding of the outcome, so the sum of the leaf values already estimates the probability of the second level; it is now clamped to the unit interval instead.
fitted_valuesis clamped the same way, so it agrees withpredict().predict()now rebuilds the model frame from the fitted terms, so a formula with a transformed term such asy ~ log(x)can be predicted from. It previously failed with a missing-predictor error.A matrix-valued term such as
poly(x, 2)raised a cryptic “missing value where TRUE/FALSE needed” during fitting; it is now rejected with a clear message.figs()gainedsubsetandna.actionarguments, which were previously swallowed by...and silently ignored. Passingweightsnow raises an error rather than fitting an unweighted model in silence.A model that accepts no split at all predicts the outcome mean instead of zero. In classification this was a probability of zero for every observation.
Integer predictors with large values no longer overflow when the candidate cutpoints are computed.
Numeric cutpoints above the 30-candidate cap are now quantiles of the sample rather than of its distinct values, so they follow the density of the data.
Factor predictors are judged by the levels present in a node rather than by the declared level set, so a factor carrying many unused levels is no longer skipped as if it had too many levels.
A missing value in a predictor at prediction time raises a clear error, and a factor level unseen in training is rejected the way other
statsmodel functions reject it, instead of failing deep inside the tree traversal.predict()rejects an unsupportedtypeinstead of quietly returning numeric predictions.bagging_figs()records the mode that was actually fitted. A factor outcome with the defaultmode = "regression"produced an ensemble that returned numeric scores instead of class predictions. Bagged classification also averages member probabilities rather than hard labels, and supportstype = "prob". A character outcome is converted to a factor once, so a bootstrap resample that misses the minority class no longer aborts the fit.fit_figs()no longer drops a predictor genuinely named.outcome.plot()validatesstyleandtree_idxinstead of rendering the wrong style silently or failing with an internal error onNA. The"classic"style labels leavesdy =, like the other styles, because a leaf holds one tree’s contribution rather than the prediction.Registering the
parsnipmodel is now idempotent, so reloading the package in a live session no longer errors.
New features
figs_tree()gained anengineargument defaulting to"figsr", and anupdate()method, so specifications behave like the rest ofparsnip.print()reports which predictors actually carry a split, andsummary()states that classification leaf values are contributions to the probability of the second class.
Documentation
- The
Descriptionfield no longer quotes acronyms, following the request from CRAN. - Help pages are rendered from markdown, so inline code and cross-references appear as such.
- The introductory vignette covers prediction, importance, plotting, classification,
parsnipintegration and bagging, and its example data no longer draws the outcome independently of the predictors.
figsr 0.1.0
CRAN release: 2026-08-31
First release.
figs()fits Fast Interpretable Greedy-Tree Sums for regression and two-class classification, growing a sum of shallow trees by greedily taking the split that most reduces residual impurity, whether that split opens a new tree or deepens an existing one.figs_tree()registers the model withparsnip, so FIGS can be used insidetidymodelsworkflows.max_splits()andmax_trees()providedialsparameter objects for tuning;min_nreusesdials::min_n().summary()prints the tree sum as IF-THEN decision rules andplot()draws the trees, in a"scientific","modern"or"classic"style.figsr_importance()ranks predictors by the total residual sum-of-squares reduction attributable to each of them.bagging_figs()fits a bootstrap ensemble of FIGS models.
