Spaces:
Sleeping
Prompt β ranked list of coordinated gene modules (coherence runs)
When "Prefer coordinated gene modules" (coherence) is on, show a ranked list of the coordinated gene modules the run explored β ordered by the module's combined held-out AUROC (the group's aggregate score vs the label, on unseen patients), with each module's coherence and its individual gene AUROCs/ranks shown. This lets a real co-expressed program (e.g. cell_cycle) surface as a GROUP even when no single gene is the top separator. Read the named code first; don't assume. Airgap stays absolute. pytest + tsc after.
0. Why / honesty
A module's combined AUROC MUST be measured on the held-out split (the same train/test split the run used). Larger groups can trivially fit the training patients, so only the held-out group-AUROC is meaningful. The aggregate is parameter-free (mean of the module's genes β AUROC vs label), so there's no model to fit and no leak. Modules were explored by the GP so they carry selection bias; the held-out combined AUROC is exactly the honest check on that.
1. Harvest the modules from the run
IMPORTANT β verified data shape: engine_v2 persists each candidate with a flat gene_ids list (engine_v2/gp.py ~line 136, list(population[i].feature_ids())) plus a typed program_repr string. It does NOT store separated per-Select gene-sets. So:
- Default (v1 of this feature): a "module" = a candidate's full distinct
gene_idsset. Iterate the persisted population across all generations (GET /runs/{id}/population/{gen}βcandidates, which is the FULL population, not the SSE-trimmed top-12; harvest every generation that's persisted), take each candidate'sgene_ids, dedupe modules as unordered opaque-ID sets, keep size as a column. - Optional (only if cleanly splitting multi-Select programs matters): parse
program_reprto extract individualSelectsets β the frontend already has a parser (web/lib/programRepr.ts); a backend parser would be new work. Don't do this unless the flat-set version proves insufficient. - Drop singletons if you want modules β₯2 genes; exact-set dedupe is fine for v1 (skip Jaccard merging unless needed).
2. Score each module (all on the run's train/test split)
First reproduce the run's EXACT held-out split: the module-scoring endpoint must rebuild the same train/test partition the run used β make_split(M.index, y, test_size, random_state=seed, stratify=objective.binary) with the run's stored seed (and matching test_size/stratify), over the anonymised matrix from _prepare_lab_data(target, dataset). If the split doesn't match, "held-out" is meaningless. For every distinct module compute, on that split:
- Combined held-out AUROC β aggregate the module's genes into one per-patient score with the mean (matching
Reduce(mean)), compute orientation-agnostic AUROC vs the label on the held-out patients. This is the primary sort key. (For TMB/continuous targets use the run's metric, e.g. |spearman|, not AUROC.) - Coherence β mean absolute pairwise correlation among the module's genes, on train (the same quantity the coherence prior rewards). Shows why it's a module.
- Size β number of genes.
- Per-gene β each gene's single-gene AUROC and rank/N from the existing diagnostic (
/diagnostic/...-rank), so the user sees the individual strengths inside the group. - Add an endpoint (or extend the result endpoint) that returns this module ranking for a given run, opaque-ID only for the ranking itself.
3. UI β ranked modules
- Show this section only when coherence was on for the run (gate on the run's coherence flag).
- Render a ranked list (cards or a table), default sorted by combined held-out AUROC descending, with columns: combined AUROC Β· coherence Β· size. Let the user re-sort by coherence.
- Each module expands to its genes: revealed symbol, single-gene AUROC, rank/N β reuse the highlighted-genes styling. Mark genes that are in a reference set (p16 / cell_cycle) with the existing colour scheme, so a cell_cycle-heavy module is visually obvious.
- Header copy + a "?" explaining plainly: "Each row is a group of genes that move together (a coordinated module the engine explored). Combined AUROC = how well the group's average score separates the label on patients it never saw. A group can beat its individual genes β that's the point of looking at modules."
- Place it near the result, after the single-gene ranking. It does NOT replace the winner/ranking; it's an additional view.
4. Airgap
- The module ranking itself crosses the wire as opaque IDs + scores. Reveal symbols only for the modules actually displayed (bounded β same discipline as revealing a winner; never the whole map). If the list is long, reveal lazily per expanded module.
- Combined AUROC and coherence are computed on the anonymised matrix; no names needed to rank.
CONSTRAINTS
- Engine name-blind; reveal only the displayed modules' genes. No change to the GP search itself β this is a post-run analysis over the persisted population.
- Held-out combined AUROC only; never in-sample. No model fitting in the aggregate (mean only) so there's nothing to leak.
Checkpoint
- A coherence-on HPV run shows a ranked list of modules by combined held-out AUROC; expanding a module reveals its genes with per-gene AUROC/rank and reference-set marking.
- A cell_cycle-heavy module (if the run explored one) appears with a high combined AUROC even though its genes aren't individually top β demonstrating the group view.
- Ranking payload is opaque-only; revealed symbols are bounded to displayed modules; airgap tests green;
tsc/pytestclean.