File size: 2,329 Bytes
925ee3b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
"""Subsampling robustness analysis."""

from __future__ import annotations

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


def subsampling_robustness(
    adata: AnnData,
    fractions: list[float] | None = None,
    n_repeats: int = 3,
    random_state: int = 0,
) -> pd.DataFrame:
    """Evaluate robustness of gamma estimates by subsampling cells.

    For each fraction, subsample cells, rerun the pipeline, and correlate
    the resulting per-gene median gamma with the full-data estimate.

    Parameters
    ----------
    adata
        Fully analyzed AnnData (must have ``gamma`` layer, ``Mu``/``Ms``
        layers, and ``var['beta']``).
    fractions
        Cell fractions to test (default: [0.3, 0.5, 0.7, 0.9]).
    n_repeats
        Number of random repeats per fraction.
    random_state
        Base random seed.

    Returns
    -------
    DataFrame with columns: ``fraction``, ``repeat``, ``spearman_r``,
    ``pearson_r``, ``n_genes``.
    """
    require_layers(adata, GAMMA)

    if fractions is None:
        fractions = [0.3, 0.5, 0.7, 0.9]

    gamma_full = get_layer(adata, GAMMA)
    median_gamma_full = np.median(gamma_full, axis=0)

    rng = np.random.RandomState(random_state)
    records = []

    for frac in fractions:
        n_cells = max(int(adata.n_obs * frac), 10)
        for rep in range(n_repeats):
            idx = rng.choice(adata.n_obs, size=n_cells, replace=False)
            gamma_sub = gamma_full[idx, :]
            median_gamma_sub = np.median(gamma_sub, axis=0)

            # Remove genes with zero variance
            valid = (np.std(median_gamma_full) > 0) & (np.std(median_gamma_sub) > 0)
            if not valid:
                sp_r = pe_r = np.nan
            else:
                sp_r, _ = stats.spearmanr(median_gamma_full, median_gamma_sub)
                pe_r, _ = stats.pearsonr(median_gamma_full, median_gamma_sub)

            records.append({
                "fraction": frac,
                "repeat": rep,
                "spearman_r": float(sp_r),
                "pearson_r": float(pe_r),
                "n_genes": int(adata.n_vars),
                "n_cells_sampled": n_cells,
            })

    return pd.DataFrame(records)