Estimate nuisance values for eSVD objects (i.e., over-dispersion)
Source:R/nuisance.R
estimate_nuisance.eSVD.RdAssumes a Gamma-Poisson model where the mean and variance are proportionally
related: \(\lambda_{ji} \sim \mathrm{Gamma}(\mathrm{mean} = \mu_{ji},
\mathrm{var} = \gamma_j \mu_{ji})\). The estimated nuisance_vec is
the Gamma rate \(\beta_j = 1/\gamma_j\), the reciprocal of the
over-dispersion \(\gamma_j\) in Lin, Qiu and Roeder (2024), so a
larger value means less over-dispersion.
Usage
# S3 method for class 'eSVD'
estimate_nuisance(
input_obj,
bool_covariates_as_library = TRUE,
bool_library_includes_interept = TRUE,
bool_use_log = FALSE,
cap_multiplier = 10,
min_val = 1e-04,
verbose = 0,
...
)Arguments
- input_obj
eSVDobject output fromopt_esvd.eSVD. Specifically, the nuisance parameters will be estimated based on the fit ininput_obj[[input_obj[["latest_Fit"]]]].- bool_covariates_as_library
Boolean to include the donor covariates (every covariate other than the case-control variable) in the covariate-adjusted library size, default is
TRUE, as incompute_posterior.eSVDandcompute_test_per_geneand aseSVDpasses it. Pass the same value to all of them, or the rate and the posterior use different libraries.- bool_library_includes_interept
Boolean if the intercept term from the eSVD matrix factorization should be included in the calculation for the covariate-adjusted library size, default is
TRUE.- bool_use_log
Boolean if the nuisance (i.e., over-dispersion) parameter should be estimated on the log scale, default is
FALSE.- cap_multiplier
One positive number, default
10: no gene's rate may exceed this many times the median over cells of its library size.Infmeans no cap.- min_val
Minimum value of the rate, as a multiple of the median over cells of the gene's library size (the units of
cap_multiplier); must be belowcap_multiplier. Default1e-4.- verbose
Integer.
- ...
Additional parameters.
Value
eSVD object with the following named vectors, one entry per
gene, added to the list in input_obj[[input_obj[["latest_Fit"]]]]:
nuisance_vec (the rate after the floor and the cap, which is what
later stages read; compute_posterior still floors it at a quantile
and may rescale it), nuisance_mle_vec (the rate before the cap but
after the floor, so for a failed gene it is the floor and not an
estimate),
nuisance_library_median_vec (the median over cells of the gene's
library size, so the cap is cap_multiplier times this),
nuisance_status (a factor with levels estimated,
capped, boundary, failed; see above),
gene_mean_count_vec (the gene's mean count over cells) and
gene_sparsity_vec (the fraction of cells in which its count is
zero). input_obj$param records nuisance_cap_multiplier,
nuisance_num_capped (the number of genes whose rate the cap
replaced, the boundary genes among them included),
nuisance_num_boundary and nuisance_num_failed; calling the
function again overwrites them. plot_nuisance draws these.
Details
The cap. Each gene's rate is the maximum-likelihood estimate,
bounded above: \(\hat\beta_j = \min\{\hat\beta_j^{\mathrm{MLE}},\ c
\cdot \mathrm{median}_i\, \ell_{ji}\}\), with \(c\) =
cap_multiplier and \(\ell_{ji}\) the covariate-adjusted library
size of gene \(j\) in cell \(i\). The rate has the units of the library
size, which is why the bound is a multiple of it. The bound is a
calibration device and not an estimate of the smallest over-dispersion in
the data: a gene whose counts are no more variable around the fit than a
Poisson has no finite maximum-likelihood rate, its posterior would collapse
onto the fit, and its test statistic would be inflated. The bound limits
how much more weight the posterior may give the fit for one gene than for
the typical gene. cap_multiplier = Inf removes it and gives the
rates of version 1.1.0, except that the floor min_val is now a
multiple of the library size rather than an absolute number. cap_multiplier = 1 is close to, but not
the same as, the bound of the version that accompanied Lin, Qiu and Roeder
(2024), which was the largest library size of the gene and not a multiple
of its median. recompute_pvalue changes the multiplier on a
fitted object without estimating anything again.
The floor min_val is in the same units: no gene's rate is
below min_val times the median of its library size. On the
unit-free scale of plot_nuisance every rate therefore lies between
min_val and cap_multiplier, and no gene is above its cap.
min_val must be below cap_multiplier.
The status of each gene records what happened to it:
estimatedthe gene keeps its maximum-likelihood rate.
cappeda finite maximum-likelihood rate exists and is above the bound.
boundaryno finite maximum-likelihood rate exists: the score statistic for over-dispersion, \(D_j = \sum_i [(A_{ji} - \ell_{ji}\mu_{ji})^2 - A_{ji}] / \mu_{ji}\), is not positive. Such a gene is set to the bound, whatever value the iterations of the estimate stopped at (which is what
nuisance_mle_vecholds for it). Withcap_multiplier = Infit keeps that value.failedboth estimation routes failed and the rate is the floor,
min_valtimes the median of its library size.
Examples
set.seed(10)
sim <- generate_null(cell_per_person = 15, num_genes = 40,
num_individuals = 8)
esvd_obj <- initialize_esvd(dat = sim$obs_mat,
covariates = sim$covariates,
metadata_individual = sim$metadata_individual,
case_control_variable = "CC",
bool_intercept = TRUE,
k = 2,
lambda = 0.1)
esvd_obj <- reparameterization_esvd_covariates(input_obj = esvd_obj,
fit_name = "fit_Init",
omitted_variables = "Log_UMI")
esvd_obj <- opt_esvd(input_obj = esvd_obj,
max_iter = 5,
offset_variables = setdiff(colnames(esvd_obj$covariates), "CC"),
fit_name = "fit_First",
fit_previous = "fit_Init")
esvd_obj <- reparameterization_esvd_covariates(input_obj = esvd_obj,
fit_name = "fit_First",
omitted_variables = "Log_UMI")
esvd_obj <- estimate_nuisance(input_obj = esvd_obj)
summary(esvd_obj$fit_First$nuisance_vec)
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 3.446e-04 3.449e-01 1.358e+00 2.718e+00 3.305e+00 1.329e+01
table(esvd_obj$fit_First$nuisance_status)
#>
#> estimated capped boundary failed
#> 37 1 2 0
esvd_obj$param$nuisance_num_capped
#> [1] 3