torchcell.datamodels.schema.PseudobulkExpressionPhenotype

class PseudobulkExpressionPhenotype(*, provenance_gaps: list[~torchcell.verification.sourced.ProvenanceGap] = <factory>, graph_level: str = 'node', label_name: str = 'expression_log2_ratio', label_statistic_name: str | None = 'dispersion', expression_log2_ratio: dict[str, float], dispersion: float | None = None, n_cells: int | None = None, measurement_type: str = 'pseudobulk_scrnaseq_log2fc')[source]

Bases: Phenotype, ModelStrict

Pseudobulk single-cell RNA-seq expression: per-gene log2 fold-change vs WT, plus the per-genotype single-cell summary scalars that a bulk assay cannot provide.

Distinct from both other expression families. RNASeqExpressionPhenotype is ABSOLUTE TPM on an isolate’s own genome (a survey, no reference to ratio against); MicroarrayExpressionPhenotype is a microarray log2 ratio with a per-gene expression linear channel + per-gene n_replicates. This family is a genome-scale single-cell Perturb-seq collapsed to PSEUDOBULK per genotype: each non-essential-gene deletion’s transcriptome is compared to the WILD TYPE profiled in the SAME condition, yielding a per-gene log2 fold-change (Nadal-Ribelles 2025; scanpy logfoldchanges, Wilcoxon rank-sum DE on SCTransform log-normalized counts). The WT reference is log2 fold-change 0 for every gene (reference_centered = True).

The single-cell origin is preserved by two per-genotype scalars – the WHOLE POINT of a pseudobulk+dispersion (rather than per-cell) representation:

  • dispersion: the genotype’s transcriptional HETEROGENEITY, the standard deviation of the scaled SVD leverage score across the genotype’s cells (sd_lvscore_scaledFU2; the leverage score is z-scored against WT cells, so WT dispersion ~= 1). Higher = more deviated/heterogeneous expression vs WT.

  • n_cells: the number of assigned single cells the pseudobulk logFC was estimated from (cell_number); a per-genotype confidence weight.

Ragged gene sets: each mutant-vs-WT comparison first drops genes with 0 counts, so the tested gene set differs per genotype. A gene not tested for a genotype is KEY-ABSENT (no key), NEVER stored as 0 – honest to the source, exactly as the RNA-seq family handles genes absent from an isolate’s genome.

Provenance: Nadal-Ribelles et al. 2025, Nat. Commun. See [[torchcell.datasets.scerevisiae.nadal_ribelles2025]].

classmethod convert_and_validate_log2_ratio(v: Any) → Any[source]

Coerce log2 ratios to a SortedDict; reject empty, infinite, or NaN values.

classmethod validate_dispersion(v: float | None) → float | None[source]

Dispersion, when present, is a non-negative finite float.

classmethod validate_n_cells(v: int | None) → int | None[source]

n_cells, when present, is a positive integer.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].