Wrapper around rmoo::nsga3() (or rmoo::nsga2()) that composes registered
metric functions into a multi-objective search for compact biomarker panels.
Candidate solutions are represented as weights over a feature pool; features
with weight > 0.5 are included in the panel (up to max_features). This
threshold-based selection allows variable panel sizes, making the
num_features objective meaningful. Inputs may be a single cohort (matrix,
data.frame, or SummarizedExperiment) or multiple cohorts supplied as
lists of such objects. Optimisation should be run on training data only—use
evaluate_panel() for held-out validation.
optimize_panel(
x,
y,
objectives = define_objectives(metrics = c("sensitivity", "specificity",
"num_features")),
max_features = 5L,
feature_pool = NULL,
feature_transform = "pairwise_ratios",
feature_alignment = c("intersection", "majority", "impute_median"),
constraints = list(),
algorithm = c("NSGA-III", "NSGA-II"),
nsga_control = list(),
assay = NULL,
seed = 42L,
fitness_mode = c("cv", "in_sample", "within_cohort_val", "within_cohort_rotating",
"loco"),
fitness_cv_folds = 5L,
n_val_splits = 10L,
train_ratio = 1,
val_ratio = 0,
np_alpha = 0.15,
np_delta = 0.05,
regularized = TRUE,
regularized_alpha = 0.5,
selection_threshold = "adaptive",
record_history = FALSE,
fitness_cv = NULL
)Matrix-like object, SummarizedExperiment, or list of matrices /
experiments representing one or more cohorts.
Binary response (factor, character, or logical) aligned with
x. When x is a list, y must be a list of the same length.
Named list of objective descriptors as returned by
define_objectives().
Maximum number of biomarkers permitted in a panel. Acts
as an upper bound; actual panel size varies based on how many features have
weight > 0.5 in the decision vector. Minimum is 2 features when
regularized = TRUE (glmnet requirement), or 1 when regularized = FALSE.
NULL removes the cap (panels may use the whole feature_pool).
Optional subset of base feature identifiers (names or
integer indices) to consider during optimization. These are the original
feature names before any transformation. When using pairwise transforms,
transformed labels like "A--B" are also accepted and will be mapped
back to their constituent base features. Each cohort is subset to these
columns; no further selection is applied. Defaults to NULL, which
searches every shared feature and warns that this can be slow.
Transformation applied to selected features
after base feature selection. The NSGA algorithm selects base features,
then this transform is applied on-the-fly. Defaults to "pairwise_ratios",
which generates pairwise contrasts via pairwise_col_diff() to dampen
batch effects. Other options include "pairwise_log_ratios" (log-ratios
for compositional data), "reference_norm" (normalize relative to a
reference feature), and "none" (no transformation). Use
register_feature_transform() to add custom strategies. See
feature_transform_registry() for available options.
Strategy for aligning features across cohorts:
(Default) Keep only features present in ALL cohorts. Features missing in any cohort are dropped.
Keep features present in >= 50% of cohorts. Missing values are imputed with cohort medians.
Keep all features from any cohort. Missing values are imputed with cohort medians.
Optional list of constraint descriptors (e.g.,
from min_metric_constraint()) that must evaluate to TRUE for a candidate
solution to be considered feasible.
Multi-objective optimization algorithm. "NSGA-III"
(default) uses reference-point-based selection and gives better Pareto
front diversity for many-objective problems (3+ objectives). "NSGA-II"
uses crowding distance for diversity preservation and is typically
adequate for 2 objectives.
Named list of arguments passed to rmoo::nsga3() (or
rmoo::nsga2()). For NSGA-III, n_partitions controls reference point
density (default computed from number of objectives). Defaults to adaptive
values based on feature pool size. Note: parallel = TRUE is not recommended
as it is slower than sequential execution due to overhead.
For SummarizedExperiment inputs, assay name or index to use.
Integer seed for reproducibility (default 42L). The seed is
set once before partitioning, so both the data split and the NSGA search
are reproducible. It is set on the global RNG and is not restored on exit,
so a resampling loop around optimize_panel() must pass its own seed per
iteration. Pass NULL to leave the RNG untouched (results then vary
between runs).
How candidate panels are scored during the NSGA search:
(Default) k-fold cross-validation within the training partition; objectives are computed on out-of-fold predictions.
Train and score on the same samples. Fast but overfits; kept for small datasets and backward compatibility.
Train on the training partition, score on the
validation partition. Requires val_ratio > 0.
Pool train and validation, pre-compute
n_val_splits stratified splits, and rotate to the next split every
generation so no single split can be overfit to. Requires
val_ratio > 0.
Leave-one-cohort-out: score each candidate on concatenated out-of-cohort predictions, making cross-cohort transferability the objective. Requires at least 2 cohorts.
Number of cross-validation folds for fitness
evaluation when fitness_mode = "cv". Default is 5.
Number of rotating train/validation splits to
pre-compute when fitness_mode = "within_cohort_rotating" (default 10).
Per-cohort shares used for stratified
partitioning; the remainder (1 - train_ratio - val_ratio) is held out and
stored on the result for calibrate_panel(). The default
train_ratio = 1, val_ratio = 0 means no partitioning at all: the whole
input is the training data.
Type I error rate for Neyman-Pearson threshold selection.
Stored on the result for calibrate_panel() when a held-out partition
exists (default 0.15).
Tolerance for Neyman-Pearson threshold selection, stored
alongside np_alpha (default 0.05).
Logical; if TRUE (default), use regularized regression
(elastic net via glmnet) for scoring candidates during optimization. This
typically produces more stable fitness estimates and better out-of-sample
performance compared to unregularized logistic regression.
Elastic net mixing parameter when regularized = TRUE.
alpha = 1 is lasso, alpha = 0 is ridge, and values in between give
elastic net. Default is 0.5 (elastic net).
Either a fixed numeric threshold in (0,1) for
feature selection, or "adaptive" (default) to use gap-based selection
that allows variable panel sizes in the Pareto front. Fixed thresholds
(e.g., 0.5) tend to produce panels at max_features because more features
improve accuracy. Adaptive selection finds natural breakpoints in the
weight distribution, enabling the num_features objective to drive panel
size diversity.
Logical; if TRUE, capture the population, fitness,
and NSGA rank at every generation and attach the result to the returned
OptimizationResult. Retrieve via nsga_history(). Default FALSE.
Adds modest overhead (one matrix copy per generation) and is intended for
diagnostic / visualization use, e.g. plotting how the Pareto front
evolves over maxiter.
Deprecated. Logical alias for fitness_mode: TRUE maps
to "cv" and FALSE to "in_sample". Supplying it emits a deprecation
warning and overrides fitness_mode.
An OptimizationResult containing the Pareto-optimal solutions.
Use summarize_solutions() to inspect solutions and fit_panel() to
fit a model on a selected solution.
When train_ratio + val_ratio < 1, each cohort is stratified into
train / validation / held-out shares before the search runs; fitness_mode
determines which of these partitions
the NSGA search actually scores against (see above). The returned
OptimizationResult always carries the pooled train + validation data as
aggregated_x/aggregated_y/aggregated_cohort. The held-out partition,
np_alpha, np_delta, and partition_info are stored on control only
when a positive held-out share exists (train_ratio + val_ratio < 1); with
the default train_ratio = 1, val_ratio = 0 no partitioning happens at all
and those fields are absent. calibrate_panel() and
evaluate_pareto_solutions() read control$heldout_x /
control$heldout_y / control$heldout_cohort when present.