| """Enrichment analysis for AU-rich element (ARE) and NMD target genes.""" |
|
|
| from __future__ import annotations |
|
|
| from pathlib import Path |
|
|
| import numpy as np |
| import pandas as pd |
| from anndata import AnnData |
| from scipy import stats |
|
|
| from .._constants import GAMMA |
| from .._utils import get_layer, require_layers |
|
|
| _DATA_DIR = Path(__file__).parent / "data" |
|
|
|
|
| def _load_gene_list(filename: str) -> set[str]: |
| """Load a gene list from a bundled text file (one gene per line).""" |
| path = _DATA_DIR / filename |
| with open(path) as f: |
| return {line.strip() for line in f if line.strip()} |
|
|
|
|
| def _enrichment_test( |
| adata: AnnData, |
| gene_set: set[str], |
| label: str, |
| min_gamma_fraction: float = 0.1, |
| ) -> dict: |
| """Mann-Whitney U test: do genes in gene_set have higher gamma? |
| |
| Only tests genes with sufficient non-zero gamma signal. |
| """ |
| require_layers(adata, GAMMA) |
|
|
| gamma = get_layer(adata, GAMMA) |
| median_gamma = np.median(gamma, axis=0) |
|
|
| |
| nonzero_frac = (gamma > 0).mean(axis=0) |
| reliable = nonzero_frac >= min_gamma_fraction |
|
|
| gene_names = adata.var_names.tolist() |
| in_set = np.array([g in gene_set for g in gene_names]) |
|
|
| |
| in_set_reliable = in_set & reliable |
| background_reliable = (~in_set) & reliable |
|
|
| n_in = in_set_reliable.sum() |
| n_out = background_reliable.sum() |
|
|
| if n_in < 2 or n_out < 2: |
| return { |
| "label": label, |
| "n_genes_in_set": int(n_in), |
| "n_genes_in_set_unfiltered": int(in_set.sum()), |
| "n_genes_background": int(n_out), |
| "median_gamma_in_set": np.nan, |
| "median_gamma_background": np.nan, |
| "U_statistic": np.nan, |
| "p_value": np.nan, |
| } |
|
|
| gamma_in = median_gamma[in_set_reliable] |
| gamma_out = median_gamma[background_reliable] |
|
|
| U, p = stats.mannwhitneyu(gamma_in, gamma_out, alternative="greater") |
|
|
| return { |
| "label": label, |
| "n_genes_in_set": int(n_in), |
| "n_genes_in_set_unfiltered": int(in_set.sum()), |
| "n_genes_background": int(n_out), |
| "median_gamma_in_set": float(np.median(gamma_in)), |
| "median_gamma_background": float(np.median(gamma_out)), |
| "U_statistic": float(U), |
| "p_value": float(p), |
| } |
|
|
|
|
| def are_enrichment(adata: AnnData) -> dict: |
| """Test whether ARE genes have higher gamma than background. |
| |
| AU-rich elements (AREs) in 3' UTRs promote mRNA degradation. |
| Genes with AREs should have higher degradation rates (gamma). |
| |
| Returns |
| ------- |
| dict with test statistics including ``U_statistic`` and ``p_value``. |
| """ |
| gene_set = _load_gene_list("are_genes.txt") |
| return _enrichment_test(adata, gene_set, "ARE") |
|
|
|
|
| def nmd_enrichment(adata: AnnData) -> dict: |
| """Test whether NMD target genes have higher gamma than background. |
| |
| Nonsense-mediated mRNA decay (NMD) targets should show higher |
| degradation rates. |
| |
| Returns |
| ------- |
| dict with test statistics including ``U_statistic`` and ``p_value``. |
| """ |
| gene_set = _load_gene_list("nmd_genes.txt") |
| return _enrichment_test(adata, gene_set, "NMD") |
|
|