trackcell#
Full specification: docs/INTEGRATION.md in the repository.
Scope#
pyglmGamPoi implements the default SCT v2 offset model:
formula
y ~ log_umi→ intercept-only GLM withoffset = log(10^log10_umi)fixed slope
log_umi = log(10)output columns
theta,Intercept,log_umi(genes × 3 DataFrame)
Recommended patch in trackcell fit_offset_model:
from pyglmGamPoi import fit_offset_model, is_available
if method == "glmGamPoi_offset" and is_available():
return fit_offset_model(
umi, regressor_data, gene_index,
allow_inf_theta=allow_inf_theta,
apply_shrinkage=True,
)
Matrix layout#
Input to pyglmGamPoi: genes × cells (trackcell VST internal layout after transpose)
AnnData default: cells × genes — transpose before calling, or use
pyglmGamPoi.adata
allow_inf_theta#
When True (trackcell SCT v2 default), genes at the Poisson boundary
(overdispersion MLE = 0) receive theta = Inf, matching R
fit_glmGamPoi_offset(..., allow_inf_theta = TRUE).
When False, theta is capped at mean(mu) / 1e-4 per gene.
Parity status#
Feature |
Status |
Notes |
|---|---|---|
Per-gene intercept + offset NB |
done |
Newton + Brent; |
Cox-Reid overdispersion MLE |
done |
Local golden section + Newton; matches R |
Inf |
done |
217/217 on GSE288946 step1 vs R live |
Cross-gene |
done |
|
|
done |
|
Algorithm notes#
Overdispersion MLE uses the same Cox-Reid adjusted log-likelihood as
glmGamPoi::overdispersion_mle_impl. Optimization starts from the method-of-moments
dispersion and searches locally (log_start ± 8 on log_theta) to avoid
numerical artefacts at log_theta < -30. If the first OD pass at the initial
intercept collapses to ~Poisson, OD is retried after refitting the intercept.