ctree_stacked: Conditional Inference Tree on Stacked Multiply Imputed Data

View source: R/ctree_stacked.R

ctree_stackedR Documentation

Conditional Inference Tree on Stacked Multiply Imputed Data

Description

Fits a conditional inference tree (ctree) on stacked multiply imputed datasets using the Stack / M rescaling procedure described in Sherlock et al. (2026). Multiply imputed datasets are concatenated vertically ("stacked") and one tree is grown on the combined data. Each node-level chi-square statistic is then divided by the number of imputations (M) to counteract the artificially inflated sample size, the node-level p-values are recomputed, and the tree is compressed bottom-up. This yields a single, coherent, interpretable tree that incorporates imputation variability without requiring the pooling of structurally different trees.

Usage

ctree_stacked(
  formula,
  data,
  m = NULL,
  alpha = 0.05,
  scale_minsize = TRUE,
  verbose = TRUE,
  ...
)

Arguments

formula

A model formula, passed to partykit::ctree().

data

A mids object from mice::mice(), a list of imputed data frames, or a single complete data frame. If a single complete data frame is supplied (no missing data handling needed), the function falls back to a standard partykit::ctree() call with a warning.

m

Integer. Number of imputations to use. If data is a mids object or a list, defaults to the number of datasets available. Ignored when data is a plain data frame.

alpha

Numeric. The nominal significance threshold for node-level splitting (default 0.05). It is applied to p-values recomputed from node statistics that have been divided by m; alpha itself is not rescaled. Must be strictly between 0 and 1.

scale_minsize

Logical. If TRUE (default), minsplit and minbucket are multiplied by m so they refer to original rather than stacked observations. The partykit defaults would otherwise permit terminal nodes holding fewer than one original observation.

verbose

Logical. If TRUE (default), prints a message summarizing the stacking and correction applied.

...

Additional arguments passed to partykit::ctree_control(). Note: alpha in ... is ignored in favor of the alpha argument above.

Details

Methodological background

When data contain missing values, a common and principled approach is multiple imputation (Rubin, 1987), wherein M completed datasets are generated by drawing from the posterior predictive distribution of the missing values. For most statistical models, results from M datasets are pooled using Rubin's rules.

Conditional inference trees (ctree; Hothorn, Hornik & Zeileis, 2006) are not straightforward to pool across imputations because the tree structure itself – which variables are split, at what values, and in what order – can differ across imputations. Pooling structurally different trees produces inconsistent subgroup definitions and uninterpretable results.

Rodgers et al. (2021) proposed stacking the M imputed datasets vertically and fitting a single tree to the combined data. This circumvents the structural-mismatch problem and produces one interpretable tree. However, stacking inflates the nominal sample size by a factor of M, causing node-level test statistics to be similarly inflated and the tree to split more aggressively than warranted.

Sherlock et al. (2026) proposed and validated the Stack / M correction: each node-level test statistic computed on the stacked data is divided by M, the p-value is recomputed from the rescaled statistic, the Bonferroni adjustment for the number of candidate splitting variables is reapplied, and nodes that no longer meet alpha are pruned. See "Scope" and "Node-level calibration" below for the conditions under which the procedure has been examined and for the behavior of its node-level test.

Correction applied to the statistic, not to alpha

Rescaling the statistic is not equivalent to dividing the significance threshold by M. Writing q(p, df) for the chi-square quantile function, the two rules are:

  • statistic rescaling (correct): reject when X > M * q(1 - alpha, df)

  • threshold rescaling (incorrect): reject when X > q(1 - alpha / M, df)

These coincide only at M = 1. At df = 1, alpha = 0.05, M = 30 the first requires X > 115.2 and the second only X > 9.9, so threshold rescaling under-corrects by an order of magnitude and grows substantially larger trees than the published method.

Versions 0.1.0 and 0.2.0 of this package implemented threshold rescaling. Trees fitted with those versions are under-corrected and should be refitted.

When to use this procedure

The problem it solves is specific. Multiple imputation produces M completed datasets, and for most models their results are combined by Rubin's rules; a tree offers no estimand that can be averaged, since the M trees may split on different variables in a different order. Stacking avoids that, and the correction addresses the inflated sample size that stacking introduces. If a single interpretable tree is wanted from multiply imputed data, that is what this package is for.

In the simulations archived at the DOI given below, the procedure recovered known structure more often than listwise deletion, surrogate splits, missingness incorporated in attributes, or single imputation, and produced the most stable partitions across independent sets of imputations. Its accuracy held across missingness rates of 15% to 45% while each of those four declined, listwise deletion most steeply. Tree sizes tracked the true size closely wherever real structure was present, and were stable from M = 5 to M = 50.

Two settings matter in practice. The outcome should be included in the imputation model, which mice() does by default: omitting it attenuates the associations a tree is meant to find, at a cost described under "Node-level calibration" below. And M should follow the usual guidance for the fraction of missing information; M = 30 was used throughout these simulations.

The procedure suits least the exploratory case in which no structure may be present, since the miscalibration described below is concentrated under a true null. A single unreplicated subgroup found in data with no prior reason to expect one warrants the checks given below rather than the node-level p-value.

Scope

The procedure assumes the data are missing at random in the sense of Rubin (1976), as does the multiple imputation it is built on. In the simulations archived at the DOI given below it was examined under MCAR and MAR across a range of missingness rates, sample sizes and outcome types, and it is intended for use where missingness is plausibly at random. Under MNAR, recovery of the true structure degrades for every imputation-based approach, this one included, and a tree fitted in that setting should be treated as provisional. The mechanism is rarely known in applied work, and MNAR cannot be distinguished from MAR using the observed data, so this is a statement about where the assumption is defensible rather than a condition that can be checked.

Node-level calibration

The node-level test is not calibrated to its nominal level when the imputation model conditions on the outcome. That is recommended practice, and it is what mice() does by default when run on a data frame containing the outcome. Under a true null the test rejects more often than alpha implies, increasingly so as the missingness rate rises. Omitting the outcome from the imputation model reverses this into conservatism rather than restoring calibration, and is not recommended, since it attenuates the associations a tree is meant to detect.

Node-level p-values should therefore be read as approximate rather than nominal, and should not be reported as error rates. The recommended remedy is to treat the tree as discovery and test its partition on independent data with confirm_ctreeMI(), which pools across imputations by Rubin's rules and so has valid error control; discover_confirm() performs the whole sequence. Two further checks help in interpreting a fitted tree. node_table() reports the effective sample size behind each terminal node, in original rather than stacked observations, so a node resting on few original cases can be identified. And refitting on an independent set of imputations, then comparing the resulting partitions, indicates whether the structure is stable.

Simulations characterizing this behavior are archived at \Sexpr[results=rd]{tools:::Rd_expr_doi("10.5281/zenodo.21939940")}.

Documentation prior to version 1.0.1 described the correction as sub-nominal under MCAR. That characterization comes from the simulations in Sherlock et al. (2026), which used a marginal imputation model conditioning on neither the outcome nor the remaining predictors. It does not hold under outcome-conditioned imputation.

Usage with mice

library(mice)
imp <- mice(my_data, m = 30, printFlag = FALSE)
fit <- ctree_stacked(outcome ~ ., data = imp, alpha = 0.05)
print(fit)
plot(fit)

Usage with a list of data frames

imp_list <- lapply(1:30, function(i) complete(imp, i))
fit <- ctree_stacked(outcome ~ ., data = imp_list, alpha = 0.05)

Value

An object of class c("ctreeMI", "constparty", "party"). This inherits all methods from partykit::ctree() output and additionally carries a ctreeMI_info attribute with the following elements:

m

Number of imputations used.

n_original

Number of rows in a single imputed dataset.

n_stacked

Total rows in the stacked dataset.

alpha

The significance threshold applied to the rescaled p-values.

correction

Character, "statistic/M".

node_stats

Data frame of per-node raw statistics, degrees of freedom, rescaled statistics, p-values, and retention.

n_splits_before, n_splits_after

Splits before and after the correction was applied.

outcome_dim

Rank of the influence function of the response, i.e. the degrees of freedom carried by a numeric or ordered predictor.

minsplit, minbucket

Minimum node sizes actually used, in stacked rows.

formula

The model formula.

call

The matched call.

References

Sherlock, P., Mansolf, M., Hofheimer, J., Hockett, C. W., O'Connor, T. G., Roubinov, D., Graff, J. C., Lai, J.-S., Bush, N. R., Wright, R. J., & Chiu, Y.-H. M. (2026). Beyond linear risk: A machine learning approach to understanding perinatal depression in context. Multivariate Behavioral Research, 1-16. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1080/00273171.2026.2661244")}

Hothorn, T., Hornik, K., & Zeileis, A. (2006). Unbiased recursive partitioning: A conditional inference framework. Journal of Computational and Graphical Statistics, 15(3), 651-674. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1198/106186006X133933")}

Hothorn, T., & Zeileis, A. (2015). partykit: A modular toolkit for recursive partitioning in R. Journal of Machine Learning Research, 16, 3905-3909.

Rodgers, D. M., Jacobucci, R., & Grimm, K. J. (2021). A multiple imputation approach for handling missing data in classification and regression trees. Journal of Behavioral Data Science, 1(1), 127-153. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.35566/jbds/v1n1/p6")}

Rubin, D. B. (1987). Multiple imputation for nonresponse in surveys. Wiley.

See Also

partykit::ctree(), partykit::ctree_control(), mice::mice(), stack_imputations(), rescale_statistic(), prune_stackM(), node_table()

Examples

## Not run: 
library(mice)

# Introduce missingness into the airquality dataset
set.seed(42)
aq <- airquality
aq$Ozone[sample(nrow(aq), 20)] <- NA
aq$Solar.R[sample(nrow(aq), 15)] <- NA

# Impute
imp <- mice(aq, m = 10, printFlag = FALSE)

# Fit ctree with Stack/M correction
fit <- ctree_stacked(Ozone ~ Solar.R + Wind + Temp + Month,
                     data = imp,
                     alpha = 0.05)
print(fit)
plot(fit)

## End(Not run)


ctreeMI documentation built on Oct. 12, 2026, 5:08 p.m.