NEWS.md
biomarkerPanels to MOBID, ahead of Bioconductor submission. Replace library(biomarkerPanels) and biomarkerPanels:: / biomarkerPanels::: with library(MOBID) and MOBID:: / MOBID:::. Exported functions and S4 classes keep their names. Fitted models now store their prediction metadata under MOBID_meta; prediction falls back to the old biomarkerPanels_meta, so panels saved by biomarkerPanels still evaluate identically. Their S4 classes are recorded as belonging to biomarkerPanels, so reading them back with readRDS() still needs that package installed.select_ruleout_features() pre-filters candidates for rule-out panels by ranking each feature on the univariate specificity it reaches when its threshold captures at least target_sensitivity of cases (both directions tried). Per-cohort specificities are combined by worst cohort ("min", default) or "mean" within each direction before the better direction is kept, so a feature must separate cases the same way in every cohort. Returns a character vector like select_de_features().select_nonredundant_features() ranks candidates by greedy mRMR for panels where every slot costs an assay: relevance is the pooled limma |t| (cohort as a covariate, scaled to [0, 1]) and redundancy is within-cohort |correlation| (Spearman by default) averaged over cohorts, so shared batch structure is not counted as co-regulation. penalty = "max" (default) subtracts a candidate’s largest |correlation| with any selected feature; penalty = "mean" subtracts the average.optimize_panel() gains fitness_mode ("cv", "in_sample", "within_cohort_val", "within_cohort_rotating", "loco") plus train_ratio / val_ratio partitioning, np_alpha, np_delta, and n_val_splits — the scoring strategies and train/validation/held-out split that optimize_panel_transferable() used to provide are now built into optimize_panel() itself.fitness_cv is deprecated in favour of fitness_mode: fitness_cv = TRUE maps to fitness_mode = "cv" and fitness_cv = FALSE maps to fitness_mode = "in_sample", with a deprecation warning either way.optimize_panel_transferable() is deprecated and will be removed in the next minor release. Call optimize_panel() directly instead, e.g. optimize_panel(x, y, fitness_mode = "within_cohort_val", train_ratio = 0.7, val_ratio = 0.2).optimize_panel() (and the deprecated optimize_panel_transferable()) now default to seed = 42L, so calls that omit seed are deterministic; pass seed = NULL for the old unseeded behaviour. The seed is set on the global RNG, so downstream random steps (e.g. fit_panel()’s cv.glmnet folds) become reproducible too.optimize_panel(feature_pool = NULL) (the default) now warns that it is searching every shared feature and may be slow. optimize_panel() never selects features itself: pass a pre-selected pool to narrow the search.fitness_mode = "cv" (formerly fitness_cv = TRUE) are now drawn from the seeded RNG stream, which also makes them reproducible for a given seed (they previously were not).fake_gene_expression dataset has been removed. Generate the same data with simulate_expression_data(p = 250, n = 100, k = 4, seed = 20240220).data.frame passed as x to evaluate_panel(), evaluate_pareto_front() or the cohort helpers was mistaken for a multi-cohort list (is.list() is TRUE for data.frames), failing with “When x is a list, y must also be a list.” All cohort-list dispatch now goes through .is_cohort_list(), which excludes data.frames and SummarizedExperiments; optimize_panel_transferable() likewise rejects a bare data.frame instead of splitting its columns into cohorts.Executes the 11 resolved cleanup decisions (dev/cleanup-decisions-2026-08-RESOLVED.md). Unlike 0.1.0, several of these are deliberate behaviour changes.
select_cpop_features(), fit_cpop_panel() and colmeans_penalty() are gone. If a CPOP comparison is revisited, use the standalone CPOP package.get_top_de_features() (use select_de_features(), same arguments) and select_denominator_features() (use select_batch_associated_features(); note n_denominators is now n_features and the result field $denominators is now $features).optimize_panel(scoring_fn = ) removed — it was only honoured with fitness_cv = FALSE and regularized = FALSE. evaluate_panel(scoring_fn = ) is unchanged and remains the supported no-model scoring path.cache_fitness and cache_max_entries removed from optimize_panel() and optimize_panel_transferable(); the fitness cache is now always on, with no eviction (also removes an O(n^2) key-tracking cost).select_transferable_features(cv_control = ) removed; the internal cv.glmnet call now uses a fixed argument list.TransferablePanelResult loses its always-empty validation_metrics slot. Saved TransferablePanelResult RDS objects from older versions may fail class validity checks on load — re-create them with calibrate_panel().fit_panel()’s inner cross-validation now caps folds at 5 (was 10), matching the NSGA scoring paths. lambda.min can land elsewhere, so refit final-model coefficients and panel_metrics() may shift slightly; NSGA optimization output is unchanged. Re-run downstream analyses that report fitted-model numbers.cv.glmnet sites now share one internal helper (.fit_binomial_glmnet()), so the fold rule cannot drift again.fitness_mode = "loco" now has dedicated test coverage mirroring the rotating-validation tests.@noRd: man/ drops from 212 to 74 pages, leaving only exported topics. Their roxygen prose remains in the source files.dev/test_parallel_timing.R retired; its timing figures predated the shared fitness scaffold and no longer described the current code.specificity_at_sensitivity + pauc + min_cohort_auc + num_features) as a worked example.require_sign_consistency = FALSE is equivalent to sign_consistency_threshold = 0 in select_transferable_features().First versioned milestone: a behaviour-preserving cleanup of the package surface and internals.
select_panel_top_sensitivity(), select_panel_by_pathway(), metric_conditional_score_shift() and metric_easy_hard_accuracy() — and 15 registry-only metric_* functions are now internal: reach them through their registry names in define_objectives(). metric_specificity_at_sensitivity() remains exported.metric_specificity_at_sensitivity() now returns 0 (the worst achievable value) on degenerate inputs instead of erroring or returning NA, matching metric_sensitivity_at_specificity(), so it is safe as an NSGA objective.dev/cleanup-decisions-2026-08.md for the survey behind this release).