starplast.tuning
Hyperparameter walks, saved embeddings, and importing your own table.
Three jobs that belong together because they are what a user does before trusting a map:
walk_umap_iter— searchn_neighborsxmin_diston a seeded random subsample, so a sweep costs seconds rather than the minutes a full 8,140-gene UMAP takes, and yield each configuration as it is computed rather than a table at the end.walk_umapis that collected and ranked, for callers who want the answer rather than the process. The subsample is drawn with a fixed seed so two sweeps are comparable; the seed is recorded in every row.EmbeddingStore— save a coordinate set together with the fullEmbeddingSpecthat produced it. An embedding without its recipe cannot be compared with another or reported in a methods section.import_table— read a user's CSV and align it to gene ids, with regex repair when the identifier column is formatted differently.
On scoring a UMAP. There is no ground truth for "a good embedding", so the walk reports several quantities that measure different things and lets the user decide, rather than manufacturing one number:
trustworthiness does the map preserve the original neighborhoods (0-1, higher better)
continuity_proxy correlation between original and embedded pairwise distances
n_clusters_hdbscan how many clusters fall out, and how much is noise
A setting that maximises trustworthiness often produces one blob; a setting that produces many clusters often distorts. Both numbers are shown because that trade-off is the actual decision.
One configuration of a walk, complete: its scores and the map that produced them.
The walk used to hand back a table when the whole sweep had finished, so a 288-configuration sweep -- half an hour -- showed nothing at all until it ended, and the embeddings themselves were computed, scored and thrown away. A step carries the coordinates as well as the numbers, which is what lets configuration 12 be looked at while 13 is still computing.
genes is a boolean mask over the node table rather than a count, because a walk embeds a
subsample: without it there is no way to say which gene each coordinate belongs to, and a map
whose points cannot be named is a picture rather than a map.
Sweep UMAP hyperparameters, yielding each configuration as it finishes.
This is the walk; walk_umap is this collected into a table. Emitting per configuration is what
makes a sweep watchable -- rows and thumbnails appear one at a time rather than all at once at
the end -- and it costs nothing, because the embedding was being built anyway.
Given a store, every configuration is saved with its full recipe as it is computed, so a walk
that is stopped half way still leaves behind everything it had finished.
should_stop is asked before each configuration and simply ends the sweep: the caller keeps
every step already yielded. A stop is a decision that enough has been seen rather than an error,
so nothing is raised and nothing is discarded.
Sweep UMAP hyperparameters on a seeded subsample of the genes, and rank the settings.
on_step is called with each WalkStep the moment it is computed, which is how the interface
fills its table and its gallery a configuration at a time. The ranked table is still returned,
because ranking needs the whole sweep and a caller that only wants the answer should not have to
accumulate it.
Named embeddings on disk: coordinates plus the recipe that produced them.
Store coordinates with the full recipe that produced them.
Return (column, fraction_matching, needs_repair) for the likeliest identifier column.
A regex/replacement pair that would turn a malformed identifier column into canonical form.
Read a user table and return it keyed by canonical gene id.
pattern is applied to the identifier column before matching, so a column formatted
TgME49.208830 or gene|TGME49_208830|v2 can be repaired without editing the file:
import_table(df, "id", pattern=r"TgME49\.(\d+)", replacement=r"TGME49_\1")
resolve should be identity.GeneIndex-backed, so previous and strain accessions map to current
ones -- the failure that cost a published screen every one of its rows.