Source code for pyglmGamPoi.offset

"""Low-level matrix API for glmGamPoi offset fitting."""

from __future__ import annotations

from typing import Union

import numpy as np
import pandas as pd
from scipy import sparse

from pyglmGamPoi.fitting import fit_glmGamPoi_offset_matrix as _fit_matrix
from pyglmGamPoi.validate import (
    assert_model_pars_contract,
    format_model_pars,
    validate_genes_by_cells_matrix,
)


[docs] def fit_glmGamPoi_offset( umi: Union[np.ndarray, sparse.spmatrix], log10_umi: np.ndarray, *, gene_names: Union[list[str], np.ndarray, None] = None, allow_inf_theta: bool = True, apply_shrinkage: bool = True, ) -> pd.DataFrame: """ Fit glmGamPoi offset models (low-level API). For trackcell integration, prefer :func:`pyglmGamPoi.fit_offset_model` which accepts ``regressor_data`` in the same format as trackcell ``cell_attr``. Parameters ---------- umi UMI count matrix, genes × cells. log10_umi Per-cell log10 UMI values (length = n_cells). gene_names Optional gene index labels. allow_inf_theta When False, cap theta at mean(mu)/1e-4. apply_shrinkage When True (default, R ``glm_gp`` default), apply cross-gene dispersion trend via ``loc_median_fit`` and refit intercepts. Returns ------- DataFrame with columns ``theta``, ``Intercept``, ``log_umi``. """ umi_csr, n_genes, n_cells = validate_genes_by_cells_matrix(umi) log10_umi = np.asarray(log10_umi, dtype=np.float64) if len(log10_umi) != n_cells: raise ValueError("log10_umi length must match number of cells in umi") offset = np.log(np.power(10.0, log10_umi)) raw = _fit_matrix( umi_csr, offset, allow_inf_theta=allow_inf_theta, apply_shrinkage=apply_shrinkage, n_cells=n_cells, ) index = ( pd.Index(gene_names).astype(str) if gene_names is not None else pd.Index([str(i) for i in range(n_genes)]) ) model_pars = format_model_pars( np.asarray(raw["theta"], dtype=np.float64), np.asarray(raw["intercept"], dtype=np.float64), index, ) return assert_model_pars_contract(model_pars)