Fast variable selection in high-dimensional settings with control of the false discovery rate (FDR).
The T-Rex selector runs terminating random experiments with dummy variables and fuses their selected active sets into the final set of selected variables. It provably controls the false discovery rate (FDR), the expected fraction of false positives among the selected variables, at a user-defined target level while selecting as many variables as possible, and so reaches a high true positive rate (TPR). It is fast and memory-efficient enough for designs with millions of variables, as they arise in genomics or financial engineering. Since version 2.0.0 the R package provides bindings to the TRexSelector C++ library, which replaces the pure-R implementation of the 1.x releases under the same package name.
The method family is published in a series of papers. The two main journal articles are
J. Machkour, M. Muma, and D. P. Palomar, “The terminating-random experiments selector: Fast high-dimensional variable selection with false discovery rate control,” Signal Processing, vol. 231, article 109894, 2025. (https://doi.org/10.1016/j.sigpro.2025.109894)
J. Machkour, M. Muma, and D. P. Palomar, “High-dimensional false discovery rate control for dependent variables,” Signal Processing, vol. 234, article 109990, 2025. (https://doi.org/10.1016/j.sigpro.2025.109990)
The References section of the repository (see Links) lists the others, and the help page of every class names the papers it builds on.
The released package is on the Comprehensive R Archive Network (CRAN). Install it from an R session:
install.packages("TRexSelector")trex_get_max_threads() returns 1, which is also the check
after an installation. The CRAN binary for Windows is built with OpenMP.
On Linux, install.packages() compiles from source with the
OpenMP flags of R, so the build has OpenMP. CRAN’s R for macOS has no
OpenMP, so the macOS binary runs on one thread, while a build from
source has OpenMP when Homebrew’s libomp is installed (the next block),
because configure compiles with its omp.h and
links the OpenMP runtime that R ships.TREX_OPENMP=no forces the single-threaded build
on every platform, for example
TREX_OPENMP=no R CMD INSTALL R/TRexSelector.For a threaded build on macOS, install libomp with Homebrew and then the package from source:
brew install libompinstall.packages("TRexSelector", type = "source")The GitHub
repository holds the package in its R/TRexSelector/
subdirectory. The main branch carries the released sources,
the version that is on CRAN, and the development happens on the
dev_beyond branch. An install from the repository needs the
R-side prerequisites (once, from an R session):
install.packages(c("Rcpp", "RcppEigen", "BH", "Rcereal", "R6"))Then install the package from GitHub or from a local clone:
# Option 1: Install directly from GitHub (the main branch)
install.packages("remotes")
remotes::install_github("trexselector/TRexSelector", subdir = "R/TRexSelector")
# Option 2: Install from a local clone of the repository
# (from the shell, at the repository root)
# R CMD INSTALL R/TRexSelectorThe help pages open with:
library(TRexSelector)
help(package = "TRexSelector")
?TRexSelector
?trex_control
?trex_fdp
?trex_tpp
# etc.To cite the package in publications use:
citation("TRexSelector")This section illustrates the basic usage of the package on a small high-dimensional example.
First, generate a Gaussian data set with sparse support:
library(TRexSelector)
# Setup
n <- 75 # number of observations
p <- 150 # number of variables
num_act <- 3 # number of true active variables
beta <- c(rep(1, times = num_act), rep(0, times = p - num_act)) # coefficient vector
true_actives <- which(beta > 0) # indices of true active variables
# Generate Gaussian data
set.seed(123)
X <- matrix(stats::rnorm(n * p), nrow = n, ncol = p)
y <- X %*% beta + stats::rnorm(n)Second, run the T-Rex selector for a target FDR of 5%. The selectors
are R6 classes, so a selector is constructed with
$new(...), run with $select(), and read
through active fields such as $selected_indices (1-based
indices):
# Seed
set.seed(1234)
# Variable selection via T-Rex
sel <- TRexSelector$new(X, y, tFDR = 0.05, verbose = FALSE)
sel$select()
paste0("True active variables: ", paste(as.character(true_actives), collapse = ", "))
#> [1] "True active variables: 1, 2, 3"
paste0("Selected variables: ", paste(as.character(sel$selected_indices), collapse = ", "))
#> [1] "Selected variables: 1, 2, 3"For the preset target FDR of 5%, the T-Rex selector has selected all true active variables and no false positive in this example. The target FDR has to be chosen according to the requirements of the application.
Every selector of the next section follows the same pattern of
construction, $select() and inspection.
Seven selectors cover the T-Rex method family. Each takes a control list, which carries the T-solver choice, the dummy settings and the thread budgets.
| Selector | Task | Control |
|---|---|---|
TRexSelector |
FDR-controlled variable selection, the T-Rex selector | trex_control() |
TRexDASelector |
dependency-aware (DA) dummies for correlated variables, T-Rex+DA | trex_da_control() |
TRexGVSSelector |
group variable selection (GVS), T-Rex GVS | trex_gvs_control() |
TRexScreeningSelector |
fast FDR-controlled screening of many variables, Screen-T-Rex | trex_screen_control() |
TRexBiobankScreeningSelector |
phenotype screening of genomic biobank designs | trex_biobank_control() |
TRexSPCASelector |
sparse principal component analysis (SPCA) under FDR control | trex_spca_control() |
TRexTikhonovSelector |
selection with a general Tikhonov penalty matrix | trex_tikhonov_control() |
The selector runs K random experiments on a design of p variables,
each experiment with its own dummy matrix, and its L-loop calibrates the
number of dummies as a multiple L of p. The control list sets the
strategy of that loop, trex_control(lloop_strategy = ).
| Strategy | Dummies | Storage |
|---|---|---|
"STANDARD" (default) |
fresh matrices at every L step, the law of the T-Rex paper | K matrices |
"HCONCAT" |
the same K matrices grow by p columns per L step | K matrices |
"SEEDED" |
the draws of "STANDARD", re-derived from the seed at
every step |
none |
"PERMUTATION" |
permuted columns of the design | K matrices |
"PERMUTATION_SEEDED" |
the permutation re-derived from the seed | none |
"SKIPL" |
no L-loop, the cap max_dummy_multiplier is used
directly |
K matrices |
The seeded strategies store nothing and suit designs whose dummy
matrices do not fit in memory, and they select exactly as their stored
counterparts for the same seed. The dummies are standard Normal by
default, and trex_dummy_distribution() offers the other
laws. The vignette of the T-Rex selector,
vignette("v03-trex-selector"), describes every strategy and
the seeds.
Each random experiment runs a terminating solver, a T-solver, which
stops once a given number of dummies has entered its path. Twenty
T-solvers are available as R6 classes in four families,
tsolver_options() holds their options, and
trex_control(solver = ) picks the one a selector uses.
TLARS_Solver,
TLASSO_Solver, TSTEPWISE_Solver,
TSTAGEWISE_Solver, TENET_Solver,
TENETAug_Solver, TIENET_Solver,
TIENETAug_Solver and TIKNET_Solver.TOMP_Solver,
TGP_Solver, TACGP_Solver,
TMP_Solver, TOOLS_Solver and
TNCGMP_Solver.TAFS_Solver.TCDLASSO_Solver,
TCDENET_Solver, TCDIENET_Solver and
TCDTIKNET_Solver.The machine learning (ML) building blocks the selectors share are
available on their own: the scalers MLZScoreScaler and
MLLpNormScaler, the decompositions MLSVD and
MLPCA, the regressions MLRidge and
MLElasticNet with their cross-validated variants
MLRidgeCV and MLElasticNetCV, and
agglomerative clustering through ml_agglomerative_cluster()
and ml_cut_tree().
mem_matrix_from() writes a
matrix to a memory-mapped file and mem_matrix() wraps such
a file, which the selectors and T-solvers read without a copy.trex_fdp(), trex_tpp(),
trex_precision() and trex_recall() on index
sets, trex_fdp_dense() and trex_tpp_dense() on
coefficient vectors.trex_normalize_design(),
trex_dummy_distribution(), trex_gamma_to_k()
and trex_tikhonov_lambda2_power_rule().The package runs serially by default, and parallel work is opt-in.
trex_control(parallel_rnd_experiments = TRUE, max_outer_threads = m)
runs the random experiments of a selector on m threads,
trex_control(max_inner_threads = m) and
tsolver_options(n_threads = m) give the T-solvers a budget
of m threads for their passes over the design, and
trex_set_num_threads(m) sets the default budget of the
scalers, the clustering and the ML methods for the session, which
trex_get_num_threads() reads.
trex_get_max_threads() reports the threads OpenMP can run
on the machine and returns 1 without OpenMP (see Installation). A seeded
run selects the same variables whatever the thread settings. The
parallelism vignette, vignette("v13-parallelism"), explains
which layer owns the cores.
The package has an overview vignette,
vignette("TRexSelector"), and thirteen pages, listed by
browseVignettes("TRexSelector") and opened as
vignette("v03-trex-selector"). An install from GitHub
builds them with build_vignettes = TRUE, and their sources
are in the vignettes
directory of the repository.
The help page of every selector, T-solver and ML class ends with the
papers it builds on, and citation("TRexSelector") lists the
package entry and the T-Rex method papers.
citation("TRexSelector") gives the package entry and the
method papers, and CITATION.cff
at the repository root carries the citation metadata of the project. PUBLICATIONS.md
lists every paper of the method family, journal articles, conference
papers, theses and preprints.
The three papers at the theoretical core of the framework so far:
The package builds on the following software, Eigen for the linear algebra of the C++ core, Rcpp and RcppEigen for the bindings, the Boost headers of BH for the memory mapping, the cereal headers of Rcereal for the serialization and R6 for the classes, with OpenMP for the threads where the toolchain provides it:
GPL ≥ 3, see the GNU General Public License v3.
This program is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version. It is distributed WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.