Testing to detect and localize heterogeneous effects in block-randomized experiments.
This package implements the nesting (top-down) procedures detailed in Bowers and Chen (2020). It recursively splits experimental blocks, tests for treatment effects at each node, and controls familywise error using adaptive alpha adjustment — so you can ask not just whether a treatment worked, but where it worked.
Warning: development-stage package
This package is under active development. The API may change without notice, and not all procedures have proven statistical properties yet. If you use it in applied work, pin a specific commit or version and check back for updates.
Current version: 0.0.4.1009
Corrections after peer review (2026-08)
An anonymous referee at Annals of Applied Statistics worked through this package alongside our manuscript and identified genuine errors. Version 0.0.4.1008 corrects them; the pre-correction state is tagged pre-referee-fixes. If you used earlier versions, three changes matter:
-
Error loads from earlier versions are wrong and should be recomputed.
compute_error_load()implemented a different quantity from the paper’s definition (it multiplied each node’s own rejection probability back in, included a depth-1 term, and used one-tailed power), and the documented workflow fed it node sizes on a weight scale rather than headcounts. All of these understate the load, so the function could answer “no multiplicity adjustment needed” for designs that require adjustment. The corrected function implements the paper’s Definition 2 with two-tailed power and refuses non-headcount node sizes: pass a count column (e.g.blocksize = "nb"), not the defaulthwtweights, for any error-load or adaptive-alpha use. -
The branch-pruning alpha schedule’s strong-FWER guarantee is withdrawn. The theorem behind
alpha_adaptive_tree_pruned()(pruned load in the denominator, plus its switching rule) is false: an exact counterexample reaches FWER 0.063 at alpha = 0.05 with every stated hypothesis satisfied. The constructor now warns; levels are computed as before so existing analyses can be reproduced, but no strong-FWER claim attaches to them.alpha_adaptive_tree()with static budget weights retains its guarantee. -
Detection reporting now separates kinds of findings.
report_detections()gainshit_type(“single” = the block’s own test rejected; “group” = an effect was localized to the block’s parent but not attributed to specific blocks; “none” otherwise), reports the rejecting parent’s p-value (group_p) for covered blocks, never returnshit = NA, and computes every quantity at each block’s own final tested depth (earlier versions mishandled branches that stopped above the tree’s maximum depth).
Details in NEWS.md and FIX_PLAN.md. We thank the referee, whose report improved both the package and the paper.
Installation
# install.packages("remotes")
remotes::install_github("bowers-illinois-edu/manytestsr")The package includes C++ code (via Rcpp/RcppArmadillo) and requires a working C++ compiler. On macOS, install Xcode Command Line Tools; on Windows, install Rtools.
Public TODO list
Items marked with a check are done. Items without a check are open — they represent known limitations or planned work.
Key functions
| Function | Purpose |
|---|---|
find_blocks() |
Core recursive splitting and testing procedure |
compute_adaptive_alphas() |
Depth-adjusted significance levels for regular trees |
alpha_adaptive_tree_pruned() |
Branch-pruning alpha for irregular trees |
compute_error_load() |
Diagnose whether natural gating controls FWER |
splitCluster, splitEqualApprox, splitLOO, splitSpecifiedFactor
|
Splitting strategies |
pOneway, pWilcox, pIndepDist, pCombCauchyDist
|
P-value functions for different test statistics |
local_hommel_all_ps, local_simes, local_bh_all_ps
|
Local p-value adjustment |
make_results_tree, make_results_ggraph
|
Visualization of results |
Development
make document # generate roxygen2 documentation
make test # run test suite
make check # R CMD check
make build # build the package
The project uses renv for dependency management. Run make dependencies to install required packages.
Implementation notes
Distance and transformation calculations use C++ (Rcpp/RcppArmadillo) with three code paths selected by dataset size:
-
fast_dists_by_unit_arma2_par— OpenMP parallel processing (parallel = "yes") -
fast_dists_and_trans— direct matrix computation for small N -
fast_dists_and_trans_by_unit_arma— unit-by-unit computation for N > 20, avoiding large matrices in memory