oncodsl / engine_v2 /permutation.py
govindbalki's picture
Upload folder using huggingface_hub
0fff343 verified
Raw
History Blame Contribute Delete
2.73 kB
"""Permutation nulls for engine_v2.
- ``permutation_null`` (MSI / TMB): hold the winning program FIXED,
shuffle the target N times, re-evaluate against each shuffled target.
- ``unsup_random_null`` (unsupervised): there's no target to shuffle, so
the null is "random Vector-only programs scored on the same held-out
context". p = fraction of random programs with structure ≥ winner.
"""
from __future__ import annotations
import random
from typing import Sequence
import numpy as np
import pandas as pd
from engine_v2.fitness import V2Objective, evaluate_holdout
from engine_v2.nodes import ExecContext, Node
from engine_v2.types import TType
def permutation_null(
program: Node,
ctx: ExecContext,
y: np.ndarray,
*,
objective: V2Objective,
n_permutations: int = 200,
seed: int = 0,
) -> list[float]:
rng = np.random.default_rng(seed)
nulls: list[float] = []
label_key = objective.target # "msi" or "tmb"
for _ in range(n_permutations):
y_shuf = rng.permutation(y)
shuf_labels = {**ctx.labels, label_key: y_shuf}
shuf_ctx = ExecContext(M=ctx.M, clinical=ctx.clinical, labels=shuf_labels)
nulls.append(evaluate_holdout(program, shuf_ctx, y_shuf, objective=objective))
return nulls
def unsup_random_null(
ctx_test: ExecContext,
pool: Sequence[str],
*,
objective: V2Objective,
n_permutations: int = 200,
rates: dict | None = None,
max_depth: int = 4,
max_genes_per_set: int = 8,
seed: int = 0,
ctx_train: ExecContext | None = None,
) -> list[float]:
"""Random-program null for the unsupervised objective.
Sample ``n_permutations`` Vector-only programs (no target binding),
score each on ``ctx_test`` (with ``ctx_train`` so the silhouette is
out-of-sample, matching how the WINNER is now scored — otherwise the
null and the observation are not on the same scale and p is
deflated).
"""
from engine_v2.synthesize import random_program
py_rng = random.Random(seed + 9001)
nulls: list[float] = []
for _ in range(n_permutations):
prog = random_program(
py_rng,
pool,
objective_target=objective.target,
max_depth=max_depth,
max_genes_per_set=max_genes_per_set,
rates=rates,
return_type=TType.VECTOR,
)
nulls.append(
evaluate_holdout(
prog, ctx_test, None,
objective=objective, ctx_train=ctx_train,
)
)
return nulls
def permutation_p_value(observed: float, nulls: list[float]) -> float:
arr = np.asarray(nulls)
return float(((arr >= observed).sum() + 1) / (len(arr) + 1))