| Title: | Covariance-Aware Deconvolution of Bulk Transcriptomic Samples |
|---|---|
| Description: | Estimates cell-type proportions in bulk transcriptomic samples with a probabilistic convolution model that integrates the gene-gene covariance structure of purified reference profiles. Cellular ratios are recovered by maximum likelihood under a multivariate Gaussian convolution, using analytic gradients and Hessians, an isometric log-ratio reparametrisation (Helmert basis) that enforces the simplex constraint, and Marquardt-Levenberg or Newton-type optimisers. The methodology is described in Chassagnol, Nuel and Becht (2023) <doi:10.48550/arXiv.2309.09557>. |
| Authors: | Bastien Chassagnol [aut, cre, cph] (ORCID: <https://orcid.org/0000-0002-8955-2391>) |
| Maintainer: | Bastien Chassagnol <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 2.3.1 |
| Built: | 2026-10-22 22:52:44 UTC |
| Source: | https://github.com/bastienchassagnol/DeCovarT |
Pearson correlations
across Monte Carlo
replicates (and cell types). This is behavioural similarity: two
solvers can correlate near 1 while remaining systematically biased.
Hierarchical order uses Ward D2 on .
algorithm_similarity(benchmark, facet_rows = NULL, facet_cols = NULL)algorithm_similarity(benchmark, facet_rows = NULL, facet_cols = NULL)
benchmark |
List from |
facet_rows, facet_cols
|
Optional scenario columns. When supplied, correlations are computed inside each facet cell. |
A tibble with algorithm_x, algorithm_y, correlation,
and any facet columns.
plot_algorithm_similarity(), pivot_mc_estimates()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls), "rlm" = list(FUN = deconvolute_ratios_rlm) ), n = 4, cores = 1 ) algorithm_similarity(out)set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls), "rlm" = list(FUN = deconvolute_ratios_rlm) ), n = 4, cores = 1 ) algorithm_similarity(out)
The conditional law of the bulk profile is fully specified, so the
asymptotic calibrations of lrt_decovart() can be replaced by
simulation. Given plug-in moments and a composition
, the function draws
, refits DeCovarT, and returns the
empirical distribution of together
with percentile intervals.
bootstrap_decovart( y, mean_signature_matrix, Sigma, p = NULL, null_value = NULL, n_boot = 500L, level = 0.95, n_replicates = NULL, epsilon = 10^-8, itmax = 500L )bootstrap_decovart( y, mean_signature_matrix, Sigma, p = NULL, null_value = NULL, n_boot = 500L, level = 0.95, n_replicates = NULL, epsilon = 10^-8, itmax = 500L )
y |
Numeric vector of length |
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
p |
Composition to simulate from. Defaults to the MLE computed
from |
null_value |
Optional numeric vector of hypothesised ratios named by cell types; switches to the restricted bootstrap (see Details). |
n_boot |
Number of bootstrap replicates. |
level |
Confidence level for percentile intervals. |
n_replicates |
Number of bulk columns simulated per replicate; defaults to the number of observed columns. |
epsilon, itmax
|
Relative convergence tolerance and iteration
budget passed to |
Supplying null_value switches to a restricted bootstrap: replicates
are generated under the restricted MLE and the likelihood-ratio
statistic is recomputed on each, giving a Monte Carlo p-value that does
not rely on the asymptotic weights. For a composite null
the remaining nuisance proportions are profiled at their restricted
estimate, so the procedure is a plug-in (approximate) rather than an
exact bootstrap.
Reference uncertainty is not propagated here:
and are treated as known, exactly as in the
frequentist likelihood. To resample the purified observations that
produced those plug-in moments, use
reference_bootstrap_decovart().
A list with estimates ( n_boot matrix),
interval (percentile bounds), n_failed (refits that errored,
left as NA columns), p_simulated, and, when
null_value is supplied, statistic (observed ),
null_statistics, and p_value.
lrt_decovart(), chi_bar_square_pvalue(),
reference_bootstrap_decovart()
Other decovart_inference:
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) set.seed(1) bootstrap_decovart(y, mu, Sigma, n_boot = 20)$intervalmu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) set.seed(1) bootstrap_decovart(y, mu, Sigma, n_boot = 20)$interval
Draws
and refits the profile model. Percentile intervals are returned for
the composition and for the two scales. The reference moments stay
fixed.
bootstrap_single_cell( y, mean_signature_matrix, Sigma, n_boot = 200L, level = 0.95, epsilon = 1e-06, itmax = 40L )bootstrap_single_cell( y, mean_signature_matrix, Sigma, n_boot = 200L, level = 0.95, epsilon = 1e-06, itmax = 40L )
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
n_boot |
Number of replicates. |
level |
Confidence level. |
epsilon |
Relative function and step tolerances passed to
|
itmax |
Maximum number of Newton iterations. |
A list with estimates, interval, n_failed (refits that
errored, left as NA columns), scales, scale_interval and fit.
confint_single_cell(), bootstrap_decovart()
Other decovart_inference:
bootstrap_decovart(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) set.seed(1) bootstrap_single_cell(y, mu, sigma, n_boot = 5)$intervalmu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) set.seed(1) bootstrap_single_cell(y, mu, sigma, n_boot = 5)$interval
Upper-tail probability of the mixture
with constraints active on the boundary of the parameter space
and interior constraints. This is Case 9 of
(Self and Liang 1987), which
generalises the
result of (Chernoff 1954).
For the mixture collapses to the ordinary
of (Wilks 1938).
chi_bar_square_pvalue( statistic, n_boundary = 1L, df_interior = 0L, weights = NULL )chi_bar_square_pvalue( statistic, n_boundary = 1L, df_interior = 0L, weights = NULL )
statistic |
Numeric vector of observed likelihood-ratio
statistics |
n_boundary |
Integer |
df_interior |
Integer |
weights |
Optional numeric vector of length |
The binomial weights hold when the block of the Fisher information
corresponding to the active constraints is diagonal after
orthogonalisation against the nuisance block. Under correlated
constraints the mixing weights depend on the geometry of the
approximating tangent cone and the binomial choice is only an
approximation; Self and Liang also exhibit a nuisance-parameter
configuration whose limit is not a chi-square mixture. Supply
weights explicitly, or calibrate by simulation with
bootstrap_decovart(), whenever and the constrained
cell types share signal.
Numeric vector of upper-tail probabilities.
is a point mass at the origin, so its strict upper
tail is zero for every . The
component therefore only removes weight: with one active constraint and
no interior constraint the p-value is
, capped at when
. Note stats::pchisq() switches to the closed tail at
exactly q = 0 for df = 0; the strict convention is used here so the
p-value stays continuous in statistic.
Self SG, Liang K (1987). “Asymptotic Properties of Maximum Likelihood Estimators and Likelihood Ratio Tests under Nonstandard Conditions.” Journal of the American Statistical Association, 82(398), 605–610. ISSN 0162-1459. doi:10.1080/01621459.1987.10478472.
Chernoff H (1954). “On the Distribution of the Likelihood Ratio.” The Annals of Mathematical Statistics, 25(3), 573–578. ISSN 0003-4851. doi:10.1214/aoms/1177728725.
Wilks SS (1938). “The Large-Sample Distribution of the Likelihood Ratio for Testing Composite Hypotheses.” The Annals of Mathematical Statistics, 9(1), 60–62. ISSN 0003-4851. doi:10.1214/aoms/1177732360.
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
# One active boundary constraint: 50:50 mixture of chi2_0 and chi2_1. chi_bar_square_pvalue(2.71, n_boundary = 1L) # Interior (Wilks) calibration. chi_bar_square_pvalue(3.84, n_boundary = 0L, df_interior = 1L)# One active boundary constraint: 50:50 mixture of chi2_0 and chi2_1. chi_bar_square_pvalue(2.71, n_boundary = 1L) # Interior (Wilks) calibration. chi_bar_square_pvalue(3.84, n_boundary = 0L, df_interior = 1L)
Returns a length- simplex vector of the form
whose normalised Shannon entropy
compute_shannon_entropy() equals h_star. The uniform composition
(h_star = 1) and a Dirac mass (h_star = 0) are returned exactly.
composition_from_entropy(h_star, n_celltypes = 3L, nms = NULL)composition_from_entropy(h_star, n_celltypes = 3L, nms = NULL)
h_star |
Target |
n_celltypes |
Integer |
nms |
Optional names for the returned vector. |
Numeric simplex vector of length .
p <- composition_from_entropy(0.5, n_celltypes = 3L) compute_shannon_entropy(p)p <- composition_from_entropy(0.5, n_celltypes = 3L) compute_shannon_entropy(p)
Returns the -weighted mean of pairwise Jeffreys
(symmetrised KL) divergences between purified Gaussians, with the closed
form of the multivariate-normal Kullback–Leibler divergence
(https://statproofbook.github.io/P/mvn-kl.html)
with
.
If p is omitted it defaults to the equi-balanced vector , which
recovers the uniform pairwise average
.
compute_average_jeffreys(true_theta, J = NULL)compute_average_jeffreys(true_theta, J = NULL)
true_theta |
List with the generative parameters (see |
J |
Number of cell types. Defaults to the third dimension of |
Scalar average pairwise Jeffreys divergence.
compute_average_overlap(), compute_average_riemannian()
set.seed(1) theta <- list( mu = cbind(c(0, 0), c(3, 0)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) compute_average_jeffreys(theta)set.seed(1) theta <- list( mu = cbind(c(0, 0), c(3, 0)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) compute_average_jeffreys(theta)
Returns MixSim's BarOmega: the unweighted mean of pairwise overlaps
(up to the MixSim numerical convention), where
already uses the mixture weights inside the
Bayes / MAP rule of MixSim::overlap(). Do not multiply the
directional masses by again.
For MixSim's Davies quadrature becomes expensive.
The helper then switches to overlap_gaussian_mc(): stratified
Sobol draws, inverse-transform sampling through precomputed
Cholesky factors, and log-density MAP comparisons (n_mc
draws per component; default 10,000).
compute_average_overlap( true_theta, J = NULL, n_mc = 10000L, seed = NULL, verbose = TRUE )compute_average_overlap( true_theta, J = NULL, n_mc = 10000L, seed = NULL, verbose = TRUE )
true_theta |
List with the generative parameters (see |
J |
Number of cell types (components). Defaults to the third
dimension of |
n_mc |
Monte Carlo draws per component when |
seed |
Optional seed forwarded to |
verbose |
If |
Scalar average pairwise overlap (MixSim BarOmega).
overlap_gaussian_mc(), compute_average_jeffreys()
set.seed(1) theta <- list( p = c(0.5, 0.5), mu = cbind(c(0, 0), c(3, 0)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) compute_average_overlap(theta)set.seed(1) theta <- list( p = c(0.5, 0.5), mu = cbind(c(0, 0), c(3, 0)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) compute_average_overlap(theta)
Average over of the affine-invariant Riemannian metric
on the cone of symmetric positive-definite matrices,
, computed from the eigenvalues of
with .
The Frobenius chord is not used:
it leaves the cone, is not inversion-invariant, and suffers the swelling
effect. With the average is the pairwise distance.
compute_average_riemannian(true_theta, J = NULL)compute_average_riemannian(true_theta, J = NULL)
true_theta |
List with the generative parameters (see |
J |
Number of cell types. Defaults to the third dimension of |
Scalar average of over
.
a <- diag(2) b <- matrix(c(2, 0.5, 0.5, 1), nrow = 2) theta <- list( mu = cbind(c(0, 0), c(1, 0)), sigma = array(c(a, b), dim = c(2, 2, 2)) ) compute_average_riemannian(theta)a <- diag(2) b <- matrix(c(2, 0.5, 0.5, 1), nrow = 2) theta <- list( mu = cbind(c(0, 0), c(1, 0)), sigma = array(c(a, b), dim = c(2, 2, 2)) ) compute_average_riemannian(theta)
Returns three blocks: composition / regression scores, Monte Carlo
summaries (ADEMP-style), and optimisation / runtime diagnostics. When
is a matrix (or
is), cell-type Pearson correlation and Monte
Carlo summaries are computed across samples, not within a single
composition.
compute_benchmark_metrics( y, mean_signature_matrix, estimated_p, true_ratios = NULL, se = NULL, elapsed = NULL, memory_bytes = NULL, kkt_residual = NULL, numerical_converged = NULL, loglik_hat = NULL, loglik_true = NULL, converged = NULL, local_maximum = NULL, min_eigenvalue = NULL, max_eigenvalue = NULL, presence_threshold = 1e-04, level = 0.95, coverage_interval = "wilson", algorithm = NA_character_ )compute_benchmark_metrics( y, mean_signature_matrix, estimated_p, true_ratios = NULL, se = NULL, elapsed = NULL, memory_bytes = NULL, kkt_residual = NULL, numerical_converged = NULL, loglik_hat = NULL, loglik_true = NULL, converged = NULL, local_maximum = NULL, min_eigenvalue = NULL, max_eigenvalue = NULL, presence_threshold = 1e-04, level = 0.95, coverage_interval = "wilson", algorithm = NA_character_ )
y |
Numeric vector (or one-column matrix)
|
mean_signature_matrix |
Numeric matrix
|
estimated_p |
Estimated proportions: a length- |
true_ratios |
Optional ground truth with the same layout. When
omitted, reconstitution scores compare
|
se |
Optional standard errors matching |
elapsed, memory_bytes, kkt_residual
|
Optional per-sample runtime
diagnostics (recycled to |
numerical_converged |
Optional logical per sample: the solver returned a finite simplex vector. |
loglik_hat, loglik_true
|
Optional per-sample log-likelihoods used
for theoretical convergence (regret
|
converged |
Optional list of length |
local_maximum |
Optional logical per sample: ILR score small and
Hessian negative definite ( |
min_eigenvalue, max_eigenvalue
|
Optional ILR Hessian extrema. |
presence_threshold |
Threshold |
level |
Level of the Wald intervals built from |
coverage_interval |
Interval for the Monte Carlo coverage rate
|
algorithm |
Character label stored on each metrics row (typically the solver name). Recycled to length one. |
A named list with:
regression: global (one row per sample) and cell_type (one
row per cell type);
monte_carlo: one row per cell type, including theoretical_se
(filled later from expected Fisher at );
optimisation: one row per sample.
mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(paste0("g", 1:2), paste0("ct", 1:2))) y <- drop(mu %*% c(0.4, 0.6)) compute_benchmark_metrics(y, mu, estimated_p = c(0.45, 0.55), true_ratios = c(0.4, 0.6))mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(paste0("g", 1:2), paste0("ct", 1:2))) y <- drop(mu %*% c(0.4, 0.6)) compute_benchmark_metrics(y, mu, estimated_p = c(0.45, 0.55), true_ratios = c(0.4, 0.6))
For a probability vector over
classes (here: cell types), the Shannon entropy is
with the convention . Dividing by the maximum
entropy (uniform over all classes) yields
normalised Shannon entropy
so for a Dirac mass on one type and
for the uniform distribution over the
cell types. Zero masses are dropped only inside the sum; the
normaliser still uses the original class count .
This is preferable to changing the logarithm base to the number of
positive masses , which would renormalise only on the
support and hide sparsity relative to the full panel of cell types.
compute_shannon_entropy(ratios)compute_shannon_entropy(ratios)
ratios |
Numeric vector of cellular proportions
|
Scalar normalised entropy .
Panel B of the figure contrasts a peaked (type-specific, low entropy)
share vector with a flat (multi-type, high entropy) one for
classes.
compute_shannon_entropy(c(1, 0, 0)) # Dirac -> 0 compute_shannon_entropy(rep(1 / 3, 3)) # uniform -> 1compute_shannon_entropy(c(1, 0, 0)) # Dirac -> 0 compute_shannon_entropy(rep(1 / 3, 3)) # uniform -> 1
One entry point for the interior intervals of the population
convolution (covariance weights , no technical scales).
The default, method = "ilr", is confint_ilr_backtransform().
ilrWald interval for , mapped by
the inverse ILR chart.
waldDelta method on . Endpoints can
leave .
firthWald interval at the Jeffreys-penalised estimate
(fit_firth_decovart()). interval_ilr is the same estimate
mapped through the inverse chart.
profileLikelihood-ratio interval
(confint_profile_decovart()). This is the interior calibration.
A null on a face is lrt_decovart(), not an interval.
bootstrapParametric percentile interval
(bootstrap_decovart()).
referenceResample the reference, then refit
(reference_bootstrap_decovart()). Two or more donors in every
cell type use the donor bootstrap and keep the bulk fixed.
Otherwise columns are resampled within each cell type and the
bulk is regenerated. Cell-type labels are not shuffled; that
check is equivariance_check_decovart().
Columns of y share one composition. fit_decovart() instead
estimates a separate composition per column, and
confint.decovart_fit() is the per-column delta method.
confint_decovart( y, mean_signature_matrix = NULL, Sigma = NULL, method = c("ilr", "wald", "firth", "profile", "bootstrap", "reference"), level = 0.95, p = NULL, n_draws = 2000L, n_boot = 500L, seed = NULL, reference_profiles = NULL, donor_ids = NULL, resample = NULL, regenerate_bulk = NULL, ... )confint_decovart( y, mean_signature_matrix = NULL, Sigma = NULL, method = c("ilr", "wald", "firth", "profile", "bootstrap", "reference"), level = 0.95, p = NULL, n_draws = 2000L, n_boot = 500L, seed = NULL, reference_profiles = NULL, donor_ids = NULL, resample = NULL, regenerate_bulk = NULL, ... )
y |
Numeric vector of length |
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
method |
Interval to compute. See Description. |
level |
Confidence level. |
p |
Composition at which to evaluate the information. |
n_draws |
Monte Carlo size used when there are three or more cell types. Ignored for two cell types. |
n_boot |
Bootstrap size for |
seed |
Optional seed for the Monte Carlo map. The previous
random-number state is restored. |
reference_profiles, donor_ids
|
Passed to
|
resample |
|
regenerate_bulk |
Whether the reference bootstrap redraws the
bulk. |
... |
Passed to the selected method ( |
A list with method, estimate and interval. Other
elements depend on method.
lrt_decovart(), confint_single_cell()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) confint_decovart(y, mu, Sigma)$interval confint_decovart(y, mu, Sigma, method = "wald")$intervalmu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) confint_decovart(y, mu, Sigma)$interval confint_decovart(y, mu, Sigma, method = "wald")$interval
Forms a Wald interval for the unconstrained ILR coordinate
from the expected Fisher information, then
maps it to the simplex by the inverse chart
. For two cell types the map is monotone, so
the endpoints of the interval for are transformed. For
more than two cell types the joint normal draw
is transformed and the interval is the
marginal quantile of .
Every transformed draw is a composition, so the interval lies in
.
This is the default of confint_decovart(). The symmetric delta-method
interval on remains confint.decovart_fit().
Columns of y are replicates that share one composition: their number
multiplies the Fisher information.
confint_ilr_backtransform( y, mean_signature_matrix, Sigma, p = NULL, level = 0.95, n_draws = 2000L, seed = NULL, epsilon = 10^-8, itmax = 500L )confint_ilr_backtransform( y, mean_signature_matrix, Sigma, p = NULL, level = 0.95, n_draws = 2000L, seed = NULL, epsilon = 10^-8, itmax = 500L )
y |
Numeric vector of length |
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
p |
Composition at which to evaluate the information. |
level |
Confidence level. |
n_draws |
Monte Carlo size used when there are three or more cell types. Ignored for two cell types. |
seed |
Optional seed for the Monte Carlo map. The previous
random-number state is restored. |
epsilon, itmax
|
Relative convergence tolerance and iteration
budget passed to |
A list with estimate, interval on the simplex, rho,
rho_interval (component-wise Wald bounds for ),
vcov_rho, vcov, mapping ("endpoint" or "monte_carlo") and
n_obs. On a simplex face the interval is NA.
confint_decovart(), vcov_ilr_delta(),
confint.decovart_fit()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) confint_ilr_backtransform(y, mu, Sigma)$intervalmu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) confint_ilr_backtransform(y, mu, Sigma)$interval
Inverts the likelihood-ratio test of lrt_decovart() coordinate by
coordinate: the interval collects every with
. Because likelihood ratios are invariant
under reparametrisation, the interval respects
without the delta-method linearisation that makes
Wald intervals unreliable near a simplex face.
confint_profile_decovart( y, mean_signature_matrix, Sigma, level = 0.95, celltypes = colnames(mean_signature_matrix), epsilon = 10^-8, itmax = 500L )confint_profile_decovart( y, mean_signature_matrix, Sigma, level = 0.95, celltypes = colnames(mean_signature_matrix), epsilon = 10^-8, itmax = 500L )
y |
Numeric vector of length |
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
level |
Confidence level |
celltypes |
Names of the cell types to profile (columns of
|
epsilon, itmax
|
Relative convergence tolerance and iteration
budget passed to |
A matrix with one row per cell type and columns estimate,
lower, upper.
confint.decovart_fit() for the Wald analogue,
lrt_decovart()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) confint_profile_decovart(y, mu, Sigma)mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) confint_profile_decovart(y, mu, Sigma)
Inverts the likelihood-ratio test for one coordinate of the profile
log-likelihood. The two scales are concentrated out at every trial
value. An endpoint that lands on a face is not a Wilks interval;
use lrt_single_cell() for a boundary null.
confint_profile_single_cell( y, mean_signature_matrix, Sigma, level = 0.95, celltypes = colnames(mean_signature_matrix), variance = c("ml", "reml"), epsilon = 1e-08, itmax = 100L )confint_profile_single_cell( y, mean_signature_matrix, Sigma, level = 0.95, celltypes = colnames(mean_signature_matrix), variance = c("ml", "reml"), epsilon = 1e-08, itmax = 100L )
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
level |
Confidence level. |
celltypes |
Cell types to profile. Defaults to every column. |
variance |
|
epsilon |
Relative function and step tolerances passed to
|
itmax |
Maximum number of Newton iterations. |
A matrix with columns estimate, lower and upper.
confint_single_cell(), lrt_single_cell()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) confint_profile_single_cell(y, mu, sigma)mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) confint_profile_single_cell(y, mu, sigma)
The composition and the two technical scales are separated by the
Schur complement of the observed Hessian. method chooses the
interval for the composition. The default is the inverse ILR chart
applied to a Wald interval for , using the
profile information
.
Intervals for in nuisance$interval are Wald intervals
on the log scale, mapped back by the exponential, from the Schur
complement that removes . nuisance$interval_wald
is the symmetric normal interval on the original scale. Bootstrap
methods replace both with percentile intervals.
ilrDefault. Inverse ILR chart.
waldDelta method on the composition. Endpoints can leave
.
firthWald interval at the penalised profile estimate.
interval_ilr maps that estimate through the inverse chart.
profileInterior likelihood-ratio interval. A face null is
lrt_single_cell().
bootstrapParametric percentile interval.
referenceDonor bootstrap, or a within-type cell resample
that regenerates the bulk. See
reference_bootstrap_single_cell().
These intervals treat the reference covariance as known. They do not add a sandwich or higher-order correction for that plug-in.
variance = "reml" corrects for the residual degrees of
freedom of the variance scale: covariances are inflated by
, Wald and ILR quantiles come from (a
multivariate for the ILR map when ), gets
the chi-square interval , and the profile interval uses the
cut-off of confint_profile_single_cell(). The maximum-likelihood
is biased by about , so with few genes
(, ) the "ml" intervals cover about 0.85 to 0.92
at the 0.95 level; the bootstrap methods are unaffected by variance.
confint_single_cell( y, mean_signature_matrix = NULL, Sigma = NULL, method = c("ilr", "wald", "firth", "profile", "bootstrap", "reference"), level = 0.95, variance = c("ml", "reml"), n_draws = 2000L, n_boot = 200L, seed = NULL, reference_profiles = NULL, donor_ids = NULL, resample = NULL, regenerate_bulk = NULL, ... )confint_single_cell( y, mean_signature_matrix = NULL, Sigma = NULL, method = c("ilr", "wald", "firth", "profile", "bootstrap", "reference"), level = 0.95, variance = c("ml", "reml"), n_draws = 2000L, n_boot = 200L, seed = NULL, reference_profiles = NULL, donor_ids = NULL, resample = NULL, regenerate_bulk = NULL, ... )
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
method |
Interval for the composition. See Description. |
level |
Confidence level. |
variance |
|
n_draws |
Monte Carlo size for the ILR map when |
n_boot |
Bootstrap size. |
seed |
Optional seed, restored on exit, for the ILR Monte Carlo map and for the bootstrap methods. |
reference_profiles, donor_ids, resample, regenerate_bulk
|
Passed
to |
... |
|
A list with method, estimate (the fitted composition),
interval and nuisance. Bootstrap results also include the
replicate matrices.
vcov_single_cell(), confint_decovart(), lrt_single_cell()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) fit <- confint_single_cell(y, mu, sigma) fit$interval fit$nuisance$intervalmu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) fit <- confint_single_cell(y, mu, sigma) fit$interval fit$nuisance$interval
Interval for a binomial coverage rate
from independent coverage indicators.
Wilson is the default because the parameter is bounded in
and Wald intervals behave poorly near 0 or 1.
coverage_mc_interval( covered, conf_level = 0.95, method = c("wilson", "wald", "agresti_coull") )coverage_mc_interval( covered, conf_level = 0.95, method = c("wilson", "wald", "agresti_coull") )
covered |
Logical or 0/1 coverage indicators (one per replicate). |
conf_level |
Confidence level for the interval around
|
method |
|
A list with n, successes, coverage, mcse, lower,
upper, and method.
coverage_mc_interval(c(TRUE, TRUE, TRUE, FALSE))coverage_mc_interval(c(TRUE, TRUE, TRUE, FALSE))
For each column of the bulk matrix
, estimates
with every supplied algorithm.
Samples are iterated with furrr when cores > 1; algorithms are
sequential, so workers are never nested. When covariance information
is provided, DeCovarT methods maximise
under
.
deconvolute_ratios( signature_matrix, bulk_expression, true_ratios = NULL, Sigma = NULL, deconvolution_functions = NULL, standardise = FALSE, scaled = FALSE, cores = getOption("mc.cores", 1L), coverage_interval = "wilson", verbose = FALSE, progress_every = 10L )deconvolute_ratios( signature_matrix, bulk_expression, true_ratios = NULL, Sigma = NULL, deconvolution_functions = NULL, standardise = FALSE, scaled = FALSE, cores = getOption("mc.cores", 1L), coverage_interval = "wilson", verbose = FALSE, progress_every = 10L )
signature_matrix |
Mean signature
|
bulk_expression |
Bulk matrix
|
true_ratios |
Optional ground-truth proportions: a length- |
Sigma |
Optional array
|
deconvolution_functions |
Named list; each element has |
standardise |
If |
scaled |
Deprecated. |
cores |
Number of |
coverage_interval |
Passed to |
verbose |
If |
progress_every |
Sample-progress interval when |
A named list from compute_benchmark_metrics() with
regression (global and cell-type subtables), monte_carlo, and
optimisation (per-sample elapsed time, memory, KKT residual, and
). First-generation solvers still call
repair_simplex(); the three native DeCovarT maps (ILR or
) already lie on the simplex. When Sigma is
supplied, Newton-Raphson, Marquardt-Levenberg, L-BFGS-B, BFGS
(gradient), and simulated annealing attach ILR Wald standard
errors from vcov_ilr_delta() so monte_carlo can report
coverage, mean model SE, and the SE/SD ratio. Those SEs are the
expected-Fisher delta-method bounds used by
confint.decovart_fit(), not diagonal entries of the observed
Hessian. Mean-only solvers (NNLS, LSEI) leave Wald columns
missing: those estimators do not use the convolution likelihood.
Erkkilä T, Lehmusvaara S, Ruusuvuori P, Visakorpi T, Shmulevich I, Lähdesmäki H (2010). “Probabilistic Analysis of Gene Expression Measurements from Heterogeneous Tissues.” Bioinformatics, 26. doi:10.1093/bioinformatics/btq406. Ahn J, Yuan Y, Parmigiani G, Suraokar MB, Diao L, Wistuba II, Wang W (2013). “DeMix: Deconvolution for Mixed Cancer Transcriptomes Using Raw Measured Data.” Bioinformatics (Oxford, England), 29. doi:10.1093/bioinformatics/btt301. Wang Z, Cao S, Morris JS, Ahn J, Liu R, Tyekucheva S, Gao F, Li B, Lu W, Tang X, Wistuba II, Bowden M, Mucci L, Loda M, Parmigiani G, Holmes CC, Wang W (2018). “Transcriptome Deconvolution of Heterogeneous Tumor Samples with Immune Infiltration.” iScience, 9. doi:10.1016/j.isci.2018.10.028. Anghel CV, Quon G, Haider S, Nguyen F, Deshwar AG, Morris QD, Boutros PC (2015). “ISOpureR: An R Implementation of a Computational Purification Algorithm of Mixed Tumour Profiles.” BMC Bioinformatics, 16. doi:10.1186/s12859-015-0597-x. Ogundijo OE, Wang X (2017). “A Sequential Monte Carlo Approach to Gene Expression Deconvolution.” PLOS ONE, 12. doi:10.1371/journal.pone.0186167. Hafemeister C, Satija R (2019). “Normalization and variance stabilization of single-cell RNA-seq data using regularized negative binomial regression.” Genome Biology, 20(1), 296. doi:10.1186/s13059-019-1874-1. Chion M, Leroy A (2023). “A Bayesian Framework for Multivariate Differential Analysis Accounting for Missing Data.” arXiv. doi:10.48550/arxiv.2307.08975. Newman A, Liu C, Green M, Gentles A, Feng W, Xu Y, Hoang C, Diehn M, Alizadeh A (2015). “Robust Enumeration of Cell Subsets from Tissue Expression Profiles.” Nature methods, 12. doi:10.1038/nmeth.3337.
deconvolute_ratios_Marquardt_Levenberg()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) Y <- simulate_bulk_mixture(mu, Sigma, p = c(0.5, 0.5), n = 2)$Y deconvolute_ratios( signature_matrix = mu, bulk_expression = Y, true_ratios = c(0.5, 0.5), Sigma = Sigma, deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), cores = 1 )set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) Y <- simulate_bulk_mixture(mu, Sigma, p = c(0.5, 0.5), n = 2)$Y deconvolute_ratios( signature_matrix = mu, bulk_expression = Y, true_ratios = c(0.5, 0.5), Sigma = Sigma, deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), cores = 1 )
Estimates
under the
Gaussian convolution model
subject to the simplex constraint
, .
Optimisation is performed in unconstrained ILR coordinates
via
(Marquardt–Levenberg default; see other methods below and
vignette("theory-decovart-generative-model", package = "DeCovarT")).
deconvolute_ratios_cibersort(y, mean_signature_matrix) deconvolute_ratios_rlm(y, mean_signature_matrix) deconvolute_ratios_nnls(y, mean_signature_matrix) deconvolute_ratios_deconrnaseq(y, mean_signature_matrix) deconvolute_ratios_Marquardt_Levenberg( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_simulated_annealing( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_L_BFGS_B( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_Newton_Raphson( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_gradient_descent( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 )deconvolute_ratios_cibersort(y, mean_signature_matrix) deconvolute_ratios_rlm(y, mean_signature_matrix) deconvolute_ratios_nnls(y, mean_signature_matrix) deconvolute_ratios_deconrnaseq(y, mean_signature_matrix) deconvolute_ratios_Marquardt_Levenberg( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_simulated_annealing( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_L_BFGS_B( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_Newton_Raphson( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 ) deconvolute_ratios_gradient_descent( y, mean_signature_matrix, Sigma, epsilon = 10^-4, itmax = 200, return_model = FALSE, initial_p = NULL, dirichlet_alpha = 1 )
y |
Numeric vector (or one-column matrix)
|
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
epsilon, itmax
|
Absolute convergence tolerance and maximum number of
iterations for the optimiser (same roles as |
return_model |
If |
initial_p |
Optional start: |
dirichlet_alpha |
Dirichlet concentration when
|
Plug-in signature. Argument mean_signature_matrix is the mean
, used as a proxy for the unobserved cell-type
profiles . This is the frequentist plug-in;
recovering sample-specific latents is a Bayesian / MAP problem
(.map_gaussian_convolution()).
Named numeric vector on the simplex
(ILR methods), or that list when return_model = TRUE.
Benchmark metrics are computed by deconvolute_ratios().
deconvolute_ratios_cibersort(): Linear baseline
via nu-SVR
(CIBERSORT-style); no covariance prior is used.
deconvolute_ratios_rlm(): Robust linear model
(MASS::rlm()), as in
Monaco et al. (2019).
deconvolute_ratios_nnls(): Non-negative least squares
for
(nnls::nnls()), then simplex projection.
deconvolute_ratios_deconrnaseq(): Equality- and
inequality-constrained least squares on the simplex
(limSolve::lsei()), in the spirit of deconRNASeq.
deconvolute_ratios_simulated_annealing(): Simulated annealing on
ILR coordinates (stats::optim() with
method = "SANN").
deconvolute_ratios_L_BFGS_B(): Box-constrained L-BFGS-B
directly in (stats::optim() method = "L-BFGS-B").
The box keeps each coordinate in ; the returned vector is
closed by (no repair_simplex() clipping). Wald
standard errors still use the ILR expected-Fisher map
vcov_ilr_delta(), not a -space Hessian.
deconvolute_ratios_Newton_Raphson(): Newton–Raphson on ILR
coordinates with the analytic score and observed
Hessian, safeguarded by the PORT trust region of stats::nlminb().
deconvolute_ratios_gradient_descent(): BFGS quasi-Newton ascent
on ILR coordinates (stats::optim()
method = "BFGS").
Monaco G, Lee B, Xu W, Mustafah S, Hwang YY, Carré C, Burdin N, Visan L, Ceccarelli M, Poidinger M, Zippelius A, Pedro de Magalhães J, Larbi A (2019). “RNA-Seq Signatures Normalized by mRNA Abundance Allow Absolute Deconvolution of Human Immune Cell Types.” Cell Reports, 26. doi:10.1016/j.celrep.2019.01.041.
deconvolute_ratios(), isometric_logistic(),
starting_simplex()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) y <- drop(mu %*% c(0.6, 0.4) + rnorm(2, sd = 0.1)) deconvolute_ratios_Marquardt_Levenberg(y, mu, Sigma, itmax = 50)set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) y <- drop(mu %*% c(0.6, 0.4) + rnorm(2, sd = 0.1)) deconvolute_ratios_Marquardt_Levenberg(y, mu, Sigma, itmax = 50)
Fits one bulk sample from the linear single-cell mixture
.
The start is single_cell_nuisance_scales(): nonnegative least squares
with a free scale (DeconRNASeq's quadratic programme without the simplex
equality), then the closed-form scales at that composition.
With profile = TRUE (default) the two scales are profiled out: for
every trial composition they are recomputed in closed form, so the
weight matrix is rebuilt at
every iterate, and Newton-Raphson runs on the profile log-likelihood of
the ILR coordinates (profile_loglik_single_cell_ilr()). Its
limit is the joint maximum-likelihood estimate of
, reached in one loop.
With profile = FALSE the scales stay at their start values (a
two-stage plug-in fit), which is not the joint maximum. Supplying both
mean_scale and variance_scale fixes them at those values.
Every fit uses the analytic score and observed Hessian with the PORT
trust region of stats::nlminb(): the step maximises the quadratic
model inside a ball whose radius grows or shrinks with the ratio of
actual to predicted increase; there is no line search and no fixed
step length. The returned vcov is the delta-method image of the
inverse negative profile Hessian; intervals are
confint_single_cell().
deconvolute_single_cell( y, mean_signature_matrix, Sigma, epsilon = 1e-08, itmax = 100L, profile = TRUE, initial_p = NULL, mean_scale = NULL, variance_scale = NULL, estimand = c("cellular", "transcript"), cell_size = NULL )deconvolute_single_cell( y, mean_signature_matrix, Sigma, epsilon = 1e-08, itmax = 100L, profile = TRUE, initial_p = NULL, mean_scale = NULL, variance_scale = NULL, estimand = c("cellular", "transcript"), cell_size = NULL )
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
epsilon |
Relative function and step tolerances passed to
|
itmax |
Maximum number of Newton iterations. |
profile |
If |
initial_p |
Optional open-simplex start. |
mean_scale, variance_scale
|
Optional fixed scales. Supply both or neither. |
estimand |
|
cell_size |
Optional |
A list with composition (the fitted simplex coordinate),
p, q, rho, estimand, fit_type ("profile", "two_stage"
or "fixed_scales"), mean_scale, variance_scale,
platform_scale, n_cells, cell_size, ols_scale, loglik,
convergence (0 from stats::nlminb() means success), iterations,
p_start, message, vcov_rho, vcov and vcov_nuisance
(see vcov_single_cell()). A singular information matrix is
returned as NA without failing the fit.
single_cell_nuisance_scales(),
profile_loglik_single_cell_ilr(),
deconvolute_ratios_Newton_Raphson(),
rescale_single_cell_moments()
genes <- paste0("g", 1:4) cts <- paste0("ct", 1:2) mu <- matrix( c(2, 2, 0.2, 0.2, 0.2, 0.2, 3, 3), nrow = 4, dimnames = list(genes, cts) ) sigma <- array(0, c(4, 4, 2), dimnames = list(genes, genes, cts)) sigma[,, 1] <- diag(0.05, 4) sigma[,, 2] <- diag(0.05, 4) set.seed(1) sim <- simulate_bulk_from_cells( mu, sigma, p = c(0.8, 0.2), n_cells = 2000, platform_scale = 1 ) fit <- deconvolute_single_cell(sim$Y[, 1], mu, sigma) round(fit$p, 3)genes <- paste0("g", 1:4) cts <- paste0("ct", 1:2) mu <- matrix( c(2, 2, 0.2, 0.2, 0.2, 0.2, 3, 3), nrow = 4, dimnames = list(genes, cts) ) sigma <- array(0, c(4, 4, 2), dimnames = list(genes, genes, cts)) sigma[,, 1] <- diag(0.05, 4) sigma[,, 2] <- diag(0.05, 4) set.seed(1) sim <- simulate_bulk_from_cells( mu, sigma, p = c(0.8, 0.2), n_cells = 2000, platform_scale = 1 ) fit <- deconvolute_single_cell(sim$Y[, 1], mu, sigma) round(fit$p, 3)
Summarises the generating law
at five layers: composition,
mean geometry, covariance / SPD diagnostics, network sparsity, and
tangent Fisher information (mean versus covariance split). MixSim
BarOmega and average pairwise Hellinger of the component Gaussians
are kept in descriptors (Hellinger is the unweighted pairwise mean;
hellinger_weighted is optional). Jeffreys / symmetrised KL is
returned in supplementary. Mean-geometry columns include the
highest pairwise cosine and the mean Euclidean (CLD) gap.
describe_simulation_scenario( true_theta, adjacency = NULL, active_tol = 1e-08, include_mixsim = TRUE )describe_simulation_scenario( true_theta, adjacency = NULL, active_tol = 1e-08, include_mixsim = TRUE )
true_theta |
List with |
adjacency |
Optional |
active_tol |
Threshold for counting an active simplex component. |
include_mixsim |
Logical. If |
A list with:
theta_true: the convolution parameters p, mu, sigma;
descriptors: one-row tibble of kept scenario statistics in six
families (composition, mean geometry, SPD of
, tangent Fisher, network,
component overlap). MixSim BarOmega uses compute_average_overlap()
(Davies quadrature for , Sobol Monte Carlo otherwise).
Average pairwise Hellinger and affine-invariant Riemannian
distance of the are kept alongside.
hellinger_weighted is optional. SPD columns include both
(kappa_sigma_p) and the reciprocal
(kappa_sigma_reciprocal);
supplementary: one-row tibble of Jeffreys / symmetrised KL,
recorded but not treated as a primary score;
call: the matched call (match.call()).
run_simulation_benchmark(), expected_fisher_unconstrained(),
compute_shannon_entropy(), composition_from_entropy(),
helmert_basis(), compute_average_overlap(),
compute_average_riemannian()
theta <- list( p = c(0.5, 0.5), mu = cbind(c(10, 0), c(0, 10)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) out <- describe_simulation_scenario(theta) out$descriptors$h_star out$calltheta <- list( p = c(0.5, 0.5), mu = cbind(c(10, 0), c(0, 10)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) out <- describe_simulation_scenario(theta) out$descriptors$h_star out$call
For the multivariate-normal mean–covariance map of the DeCovarT
convolution,
with
and precision
,
the expected Fisher information has entries
The first summand is the mean contribution
(an -inner product of signature columns); the
second is the covariance contribution of the quadratic map
. See the
multivariate-normal formula on
https://en.wikipedia.org/wiki/Fisher_information#Multivariate_normal_distribution.
expected_fisher_unconstrained(p, mean_signature_matrix, Sigma)expected_fisher_unconstrained(p, mean_signature_matrix, Sigma)
p |
Numeric proportions on the open simplex. |
mean_signature_matrix |
Mean signature |
Sigma |
Cell-type covariances |
Symmetric expected Fisher information matrix
.
vcov_ilr_delta(), vcov.decovart_fit(),
confint.decovart_fit(), hessian_loglik_unconstrained()
# Two cell types, bivariate Gaussians: I(p) is 2 x 2. p <- c(0.6, 0.4) mu <- cbind(c(0, 0), c(3, 0)) Sigma <- array(c(diag(2), diag(2)), dim = c(2, 2, 2)) I <- expected_fisher_unconstrained(p, mu, Sigma) I# Two cell types, bivariate Gaussians: I(p) is 2 x 2. p <- c(0.6, 0.4) mu <- cbind(c(0, 0), c(3, 0)) Sigma <- array(c(diag(2), diag(2)), dim = c(2, 2, 2)) I <- expected_fisher_unconstrained(p, mu, Sigma) I
Maximum-likelihood estimator of cellular proportions
under the multivariate Gaussian convolution
This is a variance / likelihood specification, not ordinary least
squares: cell-type covariances enter the residual law and cannot be
written as extra columns of . There is therefore no
formula / lm interface, and no predict() method for forecasting
bulk expression.
The returned object is an S3 class decovart_fit with accessors
coef(), fitted(), residuals(), vcov(), nobs(), confint(),
print(), summary() and plot(). Residuals are
; they are not OLS
residuals. Goodness of fit is the convolution log-likelihood, not
residual sum of squares.
fit_decovart( signature_matrix, bulk_expression, true_ratios = NULL, Sigma = NULL, method = c("Newton-Raphson", "Marquardt-Levenberg", "L-BFGS-B"), epsilon = 10^-4, itmax = 200, standardise = FALSE, scaled = FALSE, n_starts = 0L, boundary_tol = 1e-08 ) ## S3 method for class 'decovart_fit' print(x, ...) ## S3 method for class 'decovart_fit' summary(object, ...) ## S3 method for class 'summary.decovart_fit' print(x, ...) ## S3 method for class 'decovart_fit' coef(object, ...) ## S3 method for class 'decovart_fit' fitted(object, ...) ## S3 method for class 'decovart_fit' residuals(object, ...) ## S3 method for class 'decovart_fit' vcov(object, ...) ## S3 method for class 'decovart_fit' nobs(object, ...) ## S3 method for class 'decovart_fit' confint(object, parm, level = 0.95, ...) ## S3 method for class 'decovart_fit' plot(x, ...)fit_decovart( signature_matrix, bulk_expression, true_ratios = NULL, Sigma = NULL, method = c("Newton-Raphson", "Marquardt-Levenberg", "L-BFGS-B"), epsilon = 10^-4, itmax = 200, standardise = FALSE, scaled = FALSE, n_starts = 0L, boundary_tol = 1e-08 ) ## S3 method for class 'decovart_fit' print(x, ...) ## S3 method for class 'decovart_fit' summary(object, ...) ## S3 method for class 'summary.decovart_fit' print(x, ...) ## S3 method for class 'decovart_fit' coef(object, ...) ## S3 method for class 'decovart_fit' fitted(object, ...) ## S3 method for class 'decovart_fit' residuals(object, ...) ## S3 method for class 'decovart_fit' vcov(object, ...) ## S3 method for class 'decovart_fit' nobs(object, ...) ## S3 method for class 'decovart_fit' confint(object, parm, level = 0.95, ...) ## S3 method for class 'decovart_fit' plot(x, ...)
signature_matrix |
Mean signature
|
bulk_expression |
Bulk matrix
|
true_ratios |
Optional ground-truth proportions ( |
Sigma |
Array
|
method |
Optimiser; one of |
epsilon, itmax
|
Absolute convergence tolerance and iteration
budget, in the same roles as |
standardise |
If |
scaled |
Deprecated. |
n_starts |
Number of additional random Dirichlet starts per
sample. With |
boundary_tol |
Threshold on |
x, object
|
A |
... |
Passed to |
parm |
Kept for compatibility with |
level |
Confidence level |
Standardisation. CIBERSORT requires non-negative expression, no
missing values, and a non-log linear scale
(Newman et al. 2015). A logarithm is
concave, so Jensen's inequality shifts first and second moments and
.
A gene-wise affine map
with the
same on , and
leaves the
MLE of unchanged (equivariance).
Wald covariance. Let
.
The expected Fisher information of the unconstrained mean–covariance
map (multivariate normal; see e.g. the Wikipedia entry Fisher
information, multivariate normal) is
Cramer–Rao gives
in ILR coordinates, with
and
(jacobian_isometric_logistic()). The delta method maps the bound
back to the simplex:
An object of class decovart_fit.
Newman A, Liu C, Green M, Gentles A, Feng W, Xu Y, Hoang C, Diehn M, Alizadeh A (2015). “Robust Enumeration of Cell Subsets from Tissue Expression Profiles.” Nature methods, 12. doi:10.1038/nmeth.3337.
deconvolute_ratios(),
deconvolute_ratios_Marquardt_Levenberg(),
expected_fisher_unconstrained(), vcov_ilr_delta(),
coef.decovart_fit(), vcov.decovart_fit(),
confint.decovart_fit(), confint_decovart()
toy <- readRDS(system.file( "extdata", "toy_deconvolution.rds", package = "DeCovarT" )) fit <- fit_decovart( signature_matrix = toy$signature_matrix, bulk_expression = toy$bulk_expression, Sigma = toy$Sigma, itmax = 40 ) coef(fit) nobs(fit)toy <- readRDS(system.file( "extdata", "toy_deconvolution.rds", package = "DeCovarT" )) fit <- fit_decovart( signature_matrix = toy$signature_matrix, bulk_expression = toy$bulk_expression, Sigma = toy$Sigma, itmax = 40 ) coef(fit) nobs(fit)
Maximises
on the ILR chart. The penalty is Jeffreys' prior for the expected
Fisher information of one bulk column; extra replicate columns add
only a constant, so they do not change the penalty gradient. The
returned Wald covariance is that information multiplied by the number
of columns and evaluated at the penalised estimate.
The penalty is differentiated numerically. The log-likelihood score
stays analytic. This is not an exact removal of the
bias: the convolution is a curved exponential family.
fit_firth_decovart( y, mean_signature_matrix, Sigma, p_start = NULL, epsilon = 1e-08, itmax = 200L )fit_firth_decovart( y, mean_signature_matrix, Sigma, p_start = NULL, epsilon = 1e-08, itmax = 200L )
y |
Numeric vector of length |
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
p_start |
Start on the simplex. |
epsilon, itmax
|
Relative convergence tolerance and iteration
budget passed to |
A list with coefficients, rho, loglik (unpenalised),
penalty, penalised_loglik, vcov, vcov_rho and convergence.
Firth D (1993). “Bias Reduction of Maximum Likelihood Estimates.” Biometrika, 80(1), 27–38. doi:10.1093/biomet/80.1.27.
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) fit_firth_decovart(y, mu, Sigma)$coefficientsmu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) fit_firth_decovart(y, mu, Sigma)$coefficients
Maximises the profile log-likelihood plus half the log determinant of the observed profile information. The penalty uses the negative profile Hessian, not an expected Fisher matrix. Scales stay concentrated out, so the penalty does not add a third free scale.
fit_firth_single_cell( y, mean_signature_matrix, Sigma, epsilon = 1e-08, itmax = 80L )fit_firth_single_cell( y, mean_signature_matrix, Sigma, epsilon = 1e-08, itmax = 80L )
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
epsilon |
Relative function and step tolerances passed to
|
itmax |
Maximum number of Newton iterations. |
A list with coefficients, rho, loglik, penalty,
penalised_loglik, mean_scale, variance_scale and convergence.
confint_single_cell(), fit_firth_decovart()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) fit_firth_single_cell(y, mu, sigma)$coefficientsmu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) fit_firth_single_cell(y, mu, sigma)$coefficients
Builds
whose unit columns
realise a prescribed Gram matrix (pairwise cosines) via the
symmetric square root,
Then whenever
has unit diagonal. The default is the equicorrelation
(equicorrelation) matrix
, positive
semidefinite for . Supply target_gram to set unequal
pairwise cosines (for example two close pairs and a distant background),
provided \(R\) is symmetric nonnegative-definite.
generate_mean_signature_matrix( n_genes, n_celltypes, mean_scale = 10, target_cosine = 0, target_gram = NULL, seed = NULL, nonnegative = FALSE, gene_names = NULL, celltype_names = NULL )generate_mean_signature_matrix( n_genes, n_celltypes, mean_scale = 10, target_cosine = 0, target_gram = NULL, seed = NULL, nonnegative = FALSE, gene_names = NULL, celltype_names = NULL )
n_genes |
Integer |
n_celltypes |
Integer |
mean_scale |
Positive scalar |
target_cosine |
Numeric pairwise cosine |
target_gram |
Optional symmetric |
seed |
Optional integer. When supplied, the orthonormal frame
|
nonnegative |
If |
gene_names |
Optional character vector of length |
celltype_names |
Optional character vector of length |
Realisations are unique up to an orthogonal transformation of the gene
space: replacing by with
leaves the Gram unchanged. By
default is a deterministic thin QR frame; pass seed
for a Haar-like Gaussian frame (the global random state is restored). Cholesky is an
alternative square root used in Monte Carlo simulation; see the
how-to-build-synthetic-scenarios vignette appendix.
Numeric matrix with dimensions
.
generate_mean_signature_matrix( n_genes = 6L, n_celltypes = 2L, target_cosine = 0.5 ) k <- matrix(c(1, 0.98, 0.2, 0.98, 1, 0.2, 0.2, 0.2, 1), 3, 3) generate_mean_signature_matrix( n_genes = 8L, n_celltypes = 3L, target_gram = k )generate_mean_signature_matrix( n_genes = 6L, n_celltypes = 2L, target_cosine = 0.5 ) k <- matrix(c(1, 0.98, 0.2, 0.98, 1, 0.2, 0.2, 0.2, 1), 3, 3) generate_mean_signature_matrix( n_genes = 8L, n_celltypes = 3L, target_gram = k )
Returns the Helmert sub-matrix
with
Column contrasts the first parts against part
. This is the standard ILR basis used with
isometric_log_ratio() / isometric_logistic(); any other valid ILR
basis is for an orthogonal , which rotates
coordinates but leaves simplex geometry, eigenvalues of quadratic
forms, and unchanged.
helmert_basis(n_parts)helmert_basis(n_parts)
n_parts |
Integer |
Numeric matrix .
V <- helmert_basis(3L) crossprod(V) drop(crossprod(V, rep(1, 3)))V <- helmert_basis(3L) crossprod(V) drop(crossprod(V, rep(1, 3)))
Slice is
where ,
and
. Array shape .
hessian_isometric_logistic(z, V = NULL)hessian_isometric_logistic(z, V = NULL)
z |
Numeric vector |
V |
Optional ILR basis; see |
Numeric array used in the constrained Hessian chain rule.
hessian_isometric_logistic(c(0.2, -0.5))hessian_isometric_logistic(c(0.2, -0.5))
Inverse isometric log-ratio map
with a
Helmert basis ,
No cell type is pinned as a reference. Evaluated with a log-sum-exp
shift so large
cannot overflow.
which is well-defined because .
Requires a strictly positive composition (open simplex).
isometric_logistic(z, V = NULL) isometric_log_ratio(p, V = NULL)isometric_logistic(z, V = NULL) isometric_log_ratio(p, V = NULL)
z |
Numeric vector |
V |
Optional ILR basis; see |
p |
Numeric vector on the open simplex. |
Numeric vector on the unit simplex.
Numeric vector .
isometric_log_ratio(), helmert_basis()
z <- c(0.2, -0.5) p <- isometric_logistic(z) sum(p) isometric_log_ratio(p) isometric_logistic(c(800, 1200))z <- c(0.2, -0.5) p <- isometric_logistic(z) sum(p) isometric_log_ratio(p) isometric_logistic(c(800, 1200))
with .
jacobian_isometric_logistic(z, V = NULL)jacobian_isometric_logistic(z, V = NULL)
z |
Numeric vector |
V |
Optional ILR basis; see |
Numeric matrix .
jacobian_isometric_logistic(c(0.2, -0.5))jacobian_isometric_logistic(c(0.2, -0.5))
Tests against the unrestricted simplex with
the profile likelihood-ratio statistic
where is the restricted MLE of
restricted_mle_decovart(). Unlike the Wald interval of
confint.decovart_fit(), is invariant under the additive
log-ratio reparametrisation, because a smooth bijection leaves
likelihood ratios unchanged.
lrt_decovart( y, mean_signature_matrix, Sigma, null_value, n_boundary = NULL, boundary_tol = 1e-06, epsilon = 10^-8, itmax = 500L )lrt_decovart( y, mean_signature_matrix, Sigma, null_value, n_boundary = NULL, boundary_tol = 1e-06, epsilon = 10^-8, itmax = 500L )
y |
Numeric vector of length |
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
null_value |
Numeric vector of hypothesised ratios named by cell
types, e.g. |
n_boundary |
Optional integer override for the number of active
boundary constraints; |
boundary_tol |
Distance from 0 or 1 below which a null value counts as being on the boundary. |
epsilon, itmax
|
Relative convergence tolerance and iteration
budget passed to |
Interior null. If every tested ratio lies strictly inside
, is asymptotically
(Wilks 1938).
Boundary null. A null such as lets the parameter move
in one direction only, so the local parameter space is a half-line
rather than a vector space and Wilks' theorem fails. The limit is the
chi-bar-square mixture of chi_bar_square_pvalue(): for a single
active constraint,
Chernoff (1954),
generalised to several active constraints by
Self and Liang (1987).
Boundary calibration is selected automatically when any tested value is
within boundary_tol of 0, or when the tested values sum to one, which
forces every other ratio to zero (a null fixes
coordinates on faces); override with n_boundary. The binomial weights
of chi_bar_square_pvalue() are exact for orthogonal constraints; for
several correlated faces they approximate the weights of the tangent
cone, and bootstrap_decovart() with null_value gives a calibration
that does not rely on them.
Replication. Both calibrations are population statements: they
need replicate bulk samples that genuinely share one composition
. A single -vector supplies no replication
(genes are dependent through ,
and adding bulk samples with distinct compositions adds parameters as
fast as observations). Pass several replicate columns in y, or
calibrate by bootstrap_decovart().
A one-row data frame with columns statistic,
n_boundary, df_interior, p_value, loglik_full,
loglik_null, and calibration.
Wilks SS (1938). “The Large-Sample Distribution of the Likelihood Ratio for Testing Composite Hypotheses.” The Annals of Mathematical Statistics, 9(1), 60–62. ISSN 0003-4851. doi:10.1214/aoms/1177732360.
Self SG, Liang K (1987). “Asymptotic Properties of Maximum Likelihood Estimators and Likelihood Ratio Tests under Nonstandard Conditions.” Journal of the American Statistical Association, 82(398), 605–610. ISSN 0162-1459. doi:10.1080/01621459.1987.10478472.
chi_bar_square_pvalue(), confint_profile_decovart(),
bootstrap_decovart()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(20, 22, 18, 22, 20, 24), nrow = 2) colnames(mu) <- paste0("ct", 1:3) Sigma <- array(c(diag(2), diag(2), diag(2)), dim = c(2, 2, 3)) y <- drop(mu %*% c(0.5, 0.5, 0)) lrt_decovart(y, mu, Sigma, null_value = c(ct3 = 0))mu <- matrix(c(20, 22, 18, 22, 20, 24), nrow = 2) colnames(mu) <- paste0("ct", 1:3) Sigma <- array(c(diag(2), diag(2), diag(2)), dim = c(2, 2, 3)) y <- drop(mu %*% c(0.5, 0.5, 0)) lrt_decovart(y, mu, Sigma, null_value = c(ct3 = 0))
Compares the profiled maximum with the maximum on fixed
(passed as null_value). An interior null uses Wilks'
chi-square. A null on a face uses the chi-bar-square mixture of
chi_bar_square_pvalue(). The two technical scales are profiled
out under both hypotheses, so the degrees of freedom count
composition constraints only.
lrt_single_cell( y, mean_signature_matrix, Sigma, null_value, n_boundary = NULL, boundary_tol = 1e-06, epsilon = 1e-08, itmax = 100L )lrt_single_cell( y, mean_signature_matrix, Sigma, null_value, n_boundary = NULL, boundary_tol = 1e-06, epsilon = 1e-08, itmax = 100L )
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
null_value |
Named hypothesised ratios. |
n_boundary, boundary_tol
|
As in |
epsilon |
Relative function and step tolerances passed to
|
itmax |
Maximum number of Newton iterations. |
A one-row data frame, as for lrt_decovart().
confint_profile_single_cell(), lrt_decovart()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
multistart_decovart(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(1, 0)) + c(0.2, -0.1, 0.05, 0.05) lrt_single_cell(y, mu, sigma, null_value = c(ct2 = 0))mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) colnames(mu) <- c("ct1", "ct2") sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(1, 0)) + c(0.2, -0.1, 0.05, 0.05) lrt_single_cell(y, mu, sigma, null_value = c(ct2 = 0))
The realised DeCovarT log-likelihood is not globally concave, so a
successful convergence code, a small relative-distance-to-minimum and a
negative-definite local Hessian together establish a local maximum
only. Refitting from independent Dirichlet starts and
comparing the attained log-likelihoods is the cheapest direct probe of
a second, equally good or better mode.
multistart_decovart( y, mean_signature_matrix, Sigma, n_starts = 5L, solver = deconvolute_ratios_Newton_Raphson, loglik_tol = 1e-04, dirichlet_alpha = 1, ... )multistart_decovart( y, mean_signature_matrix, Sigma, n_starts = 5L, solver = deconvolute_ratios_Newton_Raphson, loglik_tol = 1e-04, dirichlet_alpha = 1, ... )
y |
Numeric vector (or one-column matrix)
|
mean_signature_matrix |
Numeric matrix
|
Sigma |
Array of cell-type covariances in
|
n_starts |
Number of Dirichlet restarts (in addition to the equi-balanced start). |
solver |
Solver accepting |
loglik_tol |
Two starts count as reaching the same mode when their log-likelihoods differ by less than this amount. |
dirichlet_alpha |
Concentration for those random starts (default
|
... |
Passed to |
A list with coefficients (best fit), loglik,
loglik_range, starts (matrix of per-start estimates),
logliks, and multimodal.
boundary_diagnostics(), fit_decovart()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
reference_bootstrap_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) set.seed(1) multistart_decovart(y, mu, Sigma, n_starts = 3L)$multimodalmu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) y <- drop(mu %*% c(0.6, 0.4)) set.seed(1) multistart_decovart(y, mu, Sigma, n_starts = 3L)$multimodal
Estimates the MixSim Omega map
by drawing n_mc quasi-Monte Carlo points from each component
(inverse-transform sampling of a Sobol sequence through the
Cholesky factor) and comparing log-densities. The average
pairwise overlap BarOmega is the unweighted mean of
over , matching
MixSim::overlap() / FSDA MixSim.
overlap_gaussian_mc(true_theta, n_mc = 10000L, seed = NULL, J = NULL)overlap_gaussian_mc(true_theta, n_mc = 10000L, seed = NULL, J = NULL)
true_theta |
List with |
n_mc |
Draws per component (default |
seed |
Optional RNG seed (passed to Sobol randomisation and to the uniform fallback). |
J |
Optional number of components. |
For two equal-weight components this pairwise overlap equals the
histogram similarity and therefore
(Nielsen and Sun 2018).
A list with BarOmega, MaxOmega, and OmegaMap.
Nielsen F, Sun K (2018). “Guaranteed Deterministic Bounds on the Total Variation Distance between Univariate Mixtures.” arXiv:1806.11311. doi:10.48550/arxiv.1806.11311. https://arxiv.org/abs/1806.11311.
compute_average_overlap(), compute_average_riemannian()
set.seed(1) theta <- list( p = c(0.5, 0.5), mu = cbind(c(0, 0), c(3, 0)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) overlap_gaussian_mc(theta, n_mc = 2000L)$BarOmegaset.seed(1) theta <- list( p = c(0.5, 0.5), mu = cbind(c(0, 0), c(3, 0)), sigma = array(c(diag(2), diag(2)), dim = c(2, 2, 2)) ) overlap_gaussian_mc(theta, n_mc = 2000L)$BarOmega
Turns the optimisation block of run_simulation_benchmark() into
one row per replicate, algorithm, and cell type, with the matching
true proportion from theta_true. The raincloud intervals drawn from
this table are empirical Monte Carlo quantiles of
, not confidence intervals for
(Allen et al. 2019).
pivot_mc_estimates(benchmark)pivot_mc_estimates(benchmark)
benchmark |
List returned by |
A tibble with algorithm, cell_type, estimate, p_true,
error, sample_id, and any scenario metadata columns.
Allen M, Poggiali D, Whitaker K, Marshall TR, van Langen J, Kievit RA (2019). “Raincloud Plots: A Multi-Platform Tool for Robust Data Visualization.” Wellcome Open Research, 4, 63. ISSN 2398-502X. doi:10.12688/wellcomeopenres.15191.2. https://wellcomeopenresearch.org/articles/4-63.
plot_mc_raincloud(), plot_mc_forest()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( ID = "B1", true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 2, cores = 1 ) nrow(pivot_mc_estimates(out))set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( ID = "B1", true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 2, cores = 1 ) nrow(pivot_mc_estimates(out))
ggplot2::geom_tile() display of algorithm_similarity(), with
rows and columns ordered by Ward D2 clustering of
\(1-r\). Optional dendrogram via ggdendro (Suggests), drawn to
the right of the tiles with leaves flush against the heatmap
and Ward merge heights on the axis.
plot_algorithm_similarity( benchmark, facet_rows = NULL, facet_cols = NULL, dendrogram = FALSE )plot_algorithm_similarity( benchmark, facet_rows = NULL, facet_cols = NULL, dendrogram = FALSE )
benchmark |
List from |
facet_rows, facet_cols
|
Optional scenario columns. When supplied, correlations are computed inside each facet cell. |
dendrogram |
If |
A ggplot object.
algorithm_similarity(), plot_mc_metric_dots()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls), "rlm" = list(FUN = deconvolute_ratios_rlm) ), n = 4, cores = 1 ) if (requireNamespace("ggplot2", quietly = TRUE)) { plot_algorithm_similarity(out) }set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls), "rlm" = list(FUN = deconvolute_ratios_rlm) ), n = 4, cores = 1 ) if (requireNamespace("ggplot2", quietly = TRUE)) { plot_algorithm_similarity(out) }
Dot-and-whisker display of bias, RMSE, MAE, coverage, mean interval
width, SE/SD ratio, and optimiser failure rate by algorithm and cell
type
(Allen et al. 2019).
Coverage whiskers are the Wilson interval already stored on
monte_carlo (coverage_mc_interval();
(Wilson 1927)): they are
intervals for the coverage rate, not for . Bias is
referenced at 0; coverage at 0.95; SE/SD (se_sd_ratio, mean model
SE / empirical SD) at 1. Interior Wald SEs come from
vcov_ilr_delta(). Pairwise algorithm contrasts
(MAE differences versus a reference solver on the same Monte Carlo
replicates) can be read from the raincloud of paired errors; they do
not need a second bootstrap.
plot_mc_forest( benchmark, facet_rows = NULL, facet_cols = NULL, metrics = c("bias", "rmse", "mae", "coverage", "mean_interval_width", "se_sd_ratio", "failure_rate") )plot_mc_forest( benchmark, facet_rows = NULL, facet_cols = NULL, metrics = c("bias", "rmse", "mae", "coverage", "mean_interval_width", "se_sd_ratio", "failure_rate") )
benchmark |
List from |
facet_rows, facet_cols
|
Optional column names for
|
metrics |
Character vector of summaries to display. |
A ggplot object.
Allen M, Poggiali D, Whitaker K, Marshall TR, van Langen J, Kievit RA (2019).
“Raincloud Plots: A Multi-Platform Tool for Robust Data Visualization.”
Wellcome Open Research, 4, 63.
ISSN 2398-502X.
doi:10.12688/wellcomeopenres.15191.2.
https://wellcomeopenresearch.org/articles/4-63.
Wilson EB (1927).
“Probable Inference, the Law of Succession, and Statistical Inference.”
Journal of the American Statistical Association, 22(158), 209–212.
ISSN 0162-1459.
doi:10.2307/2276774.
plot_mc_raincloud(), coverage_mc_interval(),
vcov_ilr_delta(), theme_decovart_facets()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( n_genes = 2L, cosine = 0, true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 4, cores = 1 ) if (requireNamespace("ggplot2", quietly = TRUE)) { plot_mc_forest(out, facet_cols = "cosine") }set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( n_genes = 2L, cosine = 0, true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 4, cores = 1 ) if (requireNamespace("ggplot2", quietly = TRUE)) { plot_mc_forest(out, facet_cols = "cosine") }
One panel per metric; colour is a min-max normalised score with
\(1\) = best inside that metric (and facet). Do not map a second
primary score to point size. Coverage is scored as
, so over-wide intervals that inflate
coverage are not rewarded. There is no default weighted composite.
plot_mc_metric_dots( benchmark, facet_rows = NULL, facet_cols = NULL, metrics = c("rmse", "mae", "coverage", "mean_interval_width"), weights = NULL )plot_mc_metric_dots( benchmark, facet_rows = NULL, facet_cols = NULL, metrics = c("rmse", "mae", "coverage", "mean_interval_width"), weights = NULL )
benchmark |
List from |
facet_rows, facet_cols
|
Optional column names for
|
metrics |
Character vector of summaries to display. |
weights |
Optional named numeric weights (sum to 1) used only
to add a |
A ggplot object.
plot_mc_forest(), plot_algorithm_similarity()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( cosine = 0, true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 4, cores = 1 ) if (requireNamespace("ggplot2", quietly = TRUE)) { plot_mc_metric_dots(out, facet_cols = "cosine") }set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( cosine = 0, true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 4, cores = 1 ) if (requireNamespace("ggplot2", quietly = TRUE)) { plot_mc_metric_dots(out, facet_cols = "cosine") }
Half-eye densities, dots, and empirical 50% / 95% intervals
(Allen et al. 2019) for the
Monte Carlo sampling distribution of . Default
aesthetics: numeric axis is the estimation error
(so a vertical line at 0 is bias);
the y-axis is the cell type; colour and dodge group the deconvolution
algorithm. Optional facet_rows / facet_cols split scenarios
(for example number of genes versus pairwise cosine).
plot_mc_raincloud( benchmark, quantity = c("error", "estimate"), facet_rows = NULL, facet_cols = NULL, .width = c(0.5, 0.95), include_dots = TRUE, max_dots = 2000L, max_rows = NULL, dodge_width = 0.95, slab_scale = 1.4, slab_alpha = 1, category_spacing = 1, slab = c("halfeye", "dotsinterval") )plot_mc_raincloud( benchmark, quantity = c("error", "estimate"), facet_rows = NULL, facet_cols = NULL, .width = c(0.5, 0.95), include_dots = TRUE, max_dots = 2000L, max_rows = NULL, dodge_width = 0.95, slab_scale = 1.4, slab_alpha = 1, category_spacing = 1, slab = c("halfeye", "dotsinterval") )
benchmark |
List from |
quantity |
|
facet_rows, facet_cols
|
Optional column names for
|
.width |
Passed to |
include_dots |
If |
max_dots |
Maximum rows passed to |
max_rows |
Optional cap on the plotting table (half-eye and dots). When the Monte Carlo stack is huge, subsample before drawing. |
dodge_width |
Width passed to |
slab_scale |
Slab height for |
slab_alpha |
Transparency of the density slab ( |
category_spacing |
Vertical gap between discrete y categories (cell types). Values greater than 1 insert extra space so slabs from neighbouring types do not overlap; the axis still shows the original labels. |
slab |
|
When quantity = "estimate" and slab = "halfeye", slabs use a
bounded kernel on (ggdist::density_bounded()) with a
coloured outline (slab_colour / slab_linewidth). Vertex pile-up
can leave that KDE empty; slab = "dotsinterval"
(ggdist::stat_dotsinterval()) draws quantile dots instead.
True proportions are labelled at the top of each panel (the most
abundant type to the right of its reference line; the others to the
left).
The inner interval is the central 50% of Monte Carlo replicates; the
outer interval is the central 95%. These are not confidence
intervals for .
A ggplot object.
Allen M, Poggiali D, Whitaker K, Marshall TR, van Langen J, Kievit RA (2019). “Raincloud Plots: A Multi-Platform Tool for Robust Data Visualization.” Wellcome Open Research, 4, 63. ISSN 2398-502X. doi:10.12688/wellcomeopenres.15191.2. https://wellcomeopenresearch.org/articles/4-63.
plot_mc_forest(), pivot_mc_estimates()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( n_genes = 2L, cosine = 0, true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 4, cores = 1 ) if (requireNamespace("ggdist", quietly = TRUE)) { plot_mc_raincloud(out, facet_cols = "cosine") }set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) out <- run_simulation_benchmark( tibble::tibble( n_genes = 2L, cosine = 0, true_theta = list(list(p = c(0.5, 0.5), mu = mu, sigma = Sigma)) ), deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 4, cores = 1 ) if (requireNamespace("ggdist", quietly = TRUE)) { plot_mc_raincloud(out, facet_cols = "cosine") }
The frequentist DeCovarT likelihood treats
and each as known.
In a labelled, reference-based model those moments come from purified
profiles whose cell-type names stay attached. This bootstrap
resamples the experimental units that generated the reference (donors,
by default), re-estimates the plug-in moments and refits
(Efron 1979).
reference_bootstrap_decovart( y, reference_profiles, donor_ids = NULL, method = c("donors", "cells"), n_boot = 199L, level = 0.95, regenerate_bulk = FALSE, p = NULL, n_replicates = NULL, ridge = 1e-06, epsilon = 10^-8, itmax = 500L )reference_bootstrap_decovart( y, reference_profiles, donor_ids = NULL, method = c("donors", "cells"), n_boot = 199L, level = 0.95, regenerate_bulk = FALSE, p = NULL, n_replicates = NULL, ridge = 1e-06, epsilon = 10^-8, itmax = 500L )
y |
Numeric vector of length |
reference_profiles |
Named list of |
donor_ids |
Donor (or other clustering) labels: a list named like
|
method |
One of |
n_boot |
Number of bootstrap replicates. |
level |
Confidence level for percentile intervals. |
regenerate_bulk |
If |
p |
Composition to simulate from. Defaults to the MLE computed
from |
n_replicates |
Number of bulk columns simulated per replicate; defaults to the number of observed columns. |
ridge |
Non-negative ridge multiple for the sample covariance of
each cell type. The default |
epsilon, itmax
|
Relative convergence tolerance and iteration
budget passed to |
Permuting gene order, or permuting cell-type labels of an already
averaged signature, is not a bootstrap: the first destroys the
gene-wise pairing of bulk and reference, and the second is algebraic
equivariance rather than a source of uncertainty (see
equivariance_check_decovart() and
vignette("theory-DeCovarT-MLE-properties")). The two method options
instead resample, with replacement, units that actually vary.
donorsCluster bootstrap: resample donor identifiers
within each cell type, take every purified column of the
sampled donors (a donor drawn twice is included twice), rebuild
, and refit.
This is the default: it targets biological / reference-population
uncertainty rather than technical cell-level noise alone.
cellsResample purified columns independently within each cell type (with replacement) and rebuild the plug-in moments. Use this when donor labels are unavailable.
The observed bulk is kept fixed unless
regenerate_bulk = TRUE, in which case each replicate also draws
from the fitted model, at p (the observed
MLE by default) and the moments of the full reference, and refits it
with the bootstrapped moments . Drawing
from instead would make each
refit consistent with its own moments, so the reference error would not
reach : with 60 cells per type, that
variant covered a known composition 76\
level, against 92\
When a cell type has fewer purified columns than genes, the sample
covariance is singular. A ridge ridge * mean(diag(S)) is then added
on the diagonal so that remains
factorisable. Set ridge = 0 to disable that guard (and accept
possible Cholesky failures).
A list with method, estimates ( n_boot),
interval (percentile bounds), n_failed, mean_signature_matrix /
Sigma
from the original reference, and p_hat from the original plug-in
fit.
Efron B (1979). “Bootstrap Methods: Another Look at the Jackknife.” The Annals of Statistics, 7(1), 1–26. doi:10.1214/aos/1176344552.
bootstrap_decovart(), equivariance_check_decovart()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_single_cell(),
restricted_mle_decovart(),
restricted_mle_single_cell()
set.seed(1) mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) refs <- lapply(seq_len(2), function(j) { t(MASS::mvrnorm(n = 8, mu = mu[, j], Sigma = Sigma[, , j])) }) names(refs) <- colnames(mu) donor_ids <- lapply(refs, function(x) { rep(paste0("d", 1:2), length.out = ncol(x)) }) y <- drop(mu %*% c(0.6, 0.4)) reference_bootstrap_decovart( y, refs, donor_ids = donor_ids, n_boot = 15 )$intervalset.seed(1) mu <- matrix(c(20, 40, 15, 40, 20, 25), nrow = 3) colnames(mu) <- paste0("ct", 1:2) Sigma <- array(c(diag(3), diag(3)), dim = c(3, 3, 2)) refs <- lapply(seq_len(2), function(j) { t(MASS::mvrnorm(n = 8, mu = mu[, j], Sigma = Sigma[, , j])) }) names(refs) <- colnames(mu) donor_ids <- lapply(refs, function(x) { rep(paste0("d", 1:2), length.out = ncol(x)) }) y <- drop(mu %*% c(0.6, 0.4)) reference_bootstrap_decovart( y, refs, donor_ids = donor_ids, n_boot = 15 )$interval
Resamples the reference that produced
and refits
deconvolute_single_cell(). resample = NULL uses donors when every
cell type has at least two donor labels, and otherwise resamples
columns within each cell type. The within-type resample regenerates
the bulk from the fitted single-cell law, at the original
and the original
moments, and refits it with the resampled moments, so that both the
bulk noise and the reference error enter the interval.
Shuffling cell-type names is not a reference bootstrap. It does not
redraw cells or donors, and the likelihood is equivariant under a
relabeling, so the draw would not be a source of uncertainty. That
check remains equivariance_check_decovart() for the population model.
reference_bootstrap_single_cell( y, reference_profiles, donor_ids = NULL, resample = NULL, n_boot = 100L, level = 0.95, regenerate_bulk = NULL, ridge = 1e-06, epsilon = 1e-06, itmax = 40L )reference_bootstrap_single_cell( y, reference_profiles, donor_ids = NULL, resample = NULL, n_boot = 100L, level = 0.95, regenerate_bulk = NULL, ridge = 1e-06, epsilon = 1e-06, itmax = 40L )
y |
Bulk vector of length |
reference_profiles |
Named list of gene-by-cell (or gene-by-replicate) matrices, one per cell type. |
donor_ids |
Optional list of donor labels, aligned with
|
resample |
|
n_boot |
Number of replicates. |
level |
Confidence level. |
regenerate_bulk |
|
ridge |
Ridge passed to the sample covariance, relative to its mean diagonal. |
epsilon |
Relative function and step tolerances passed to
|
itmax |
Maximum number of Newton iterations. |
A list with resample, regenerate_bulk, estimates,
interval, n_failed, scales, scale_interval and fit.
reference_bootstrap_decovart(), confint_single_cell()
Other decovart_inference:
bootstrap_decovart(),
bootstrap_single_cell(),
boundary_diagnostics(),
chi_bar_square_pvalue(),
confint_decovart(),
confint_ilr_backtransform(),
confint_profile_decovart(),
confint_profile_single_cell(),
confint_single_cell(),
equivariance_check_decovart(),
fit_firth_decovart(),
fit_firth_single_cell(),
lrt_decovart(),
lrt_single_cell(),
multistart_decovart(),
reference_bootstrap_decovart(),
restricted_mle_decovart(),
restricted_mle_single_cell()
set.seed(1) mu <- cbind(ct1 = c(2, 2, 0.2, 0.2), ct2 = c(0.2, 0.2, 3, 3)) sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) refs <- lapply(seq_len(2), function(j) { t(MASS::mvrnorm(n = 6, mu = mu[, j], Sigma = sigma[, , j])) }) names(refs) <- colnames(mu) y <- 20 * drop(mu %*% c(0.7, 0.3)) + rnorm(4, sd = 0.2) reference_bootstrap_single_cell(y, refs, n_boot = 4)$resampleset.seed(1) mu <- cbind(ct1 = c(2, 2, 0.2, 0.2), ct2 = c(0.2, 0.2, 3, 3)) sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) refs <- lapply(seq_len(2), function(j) { t(MASS::mvrnorm(n = 6, mu = mu[, j], Sigma = sigma[, , j])) }) names(refs) <- colnames(mu) y <- 20 * drop(mu %*% c(0.7, 0.3)) + rnorm(4, sd = 0.2) reference_bootstrap_single_cell(y, refs, n_boot = 4)$resample
Clips numerical under/overflow and renormalises so that
and
. This is a repair /
renormalisation step for estimated proportions, not a Euclidean
projection onto the simplex and not a statistical-identifiability
constraint.
When open = TRUE, entries on the closed-simplex boundary are nudged
into the relative interior so that isometric_log_ratio() is defined
(ILR / Marquardt / Newton starts). That open-simplex path is the
former role of starting_simplex().
repair_simplex( p, tolerance = 100 * .Machine$double.eps, open = FALSE, nms = NULL )repair_simplex( p, tolerance = 100 * .Machine$double.eps, open = FALSE, nms = NULL )
p |
Numeric vector |
tolerance |
Non-negative tolerance for treating entries as zero
(default |
open |
Logical; if |
nms |
Optional names attached to the returned vector (e.g. cell-type colnames). |
Numeric vector on the simplex (open when
open = TRUE).
compositions::clo() for compositional closure.
repair_simplex(c(0.2, 0.3, 0.5 + 1e-12)) repair_simplex(c(1, 0, 0), open = TRUE)repair_simplex(c(0.2, 0.3, 0.5 + 1e-12)) repair_simplex(c(1, 0, 0), open = TRUE)
Turns nonnegative gene-by-cell-type moments into the reference used
by the single-cell mixture. Column of the supplied mean is
normalised to a composition . Two
conventions are available; the default is the raw-covariance,
cell-fraction model of the article.
cellular_raw (default). Mean
with the covariance left as supplied. Keeping in the
mean makes the fitted composition a cell fraction, not a
transcript fraction.
transcript_raw. Library-normalised mean
and per-transcript covariance
. The fitted composition is the
transcript fraction . The physical generator
is still the cellular model: generative_mean and
generative_sigma are the moments simulate_bulk_from_cells()
should draw from.
rescale_single_cell_moments( moments, cell_size, reference = c("cellular_raw", "transcript_raw") )rescale_single_cell_moments( moments, cell_size, reference = c("cellular_raw", "transcript_raw") )
moments |
List with |
cell_size |
Positive cell sizes |
reference |
|
A list with the matrices passed to the estimator
(mean_signature_matrix, Sigma), the cellular generator
(generative_mean, generative_sigma), cell_size,
composition (), reference and
estimand ("cellular" or "transcript").
simulate_hierarchical_grn_moments(),
simulate_bulk_from_cells(),
single_cell_scenario_design()
mu <- cbind(c(2, 2, 0, 0), c(0, 0, 1, 1)) sigma <- array(rep(diag(4), 2), dim = c(4, 4, 2)) moments <- list(mean_profiles = mu, covariance_matrices = sigma) ref <- rescale_single_cell_moments(moments, c(1, 5)) colSums(ref$generative_mean)mu <- cbind(c(2, 2, 0, 0), c(0, 0, 1, 1)) sigma <- array(rep(diag(4), 2), dim = c(4, 4, 2)) moments <- list(mean_profiles = mu, covariance_matrices = sigma) ref <- rescale_single_cell_moments(moments, c(1, 5)) colSums(ref$generative_mean)
Wrapper around simulate_bulk_mixture(), deconvolute_ratios(), and
compute_benchmark_metrics() (called inside deconvolute_ratios()).
Each row of scenario_config describes one generative model
(, ,
) stored in a list column true_theta. Scenario
rows are always evaluated sequentially to avoid nested
parallelism; sample-level workers live only in
deconvolute_ratios(). Scenario builders (factorial grids, overlap
summaries, etc.) should live in analysis scripts; see
scripts/fig02_bivariate_toy.R and the paper-scenario vignettes.
run_simulation_benchmark( scenario_config, deconvolution_functions, n = 200, standardise = FALSE, scaled = FALSE, cores = 1L, coverage_interval = "wilson", verbose = FALSE, progress_every = 10L )run_simulation_benchmark( scenario_config, deconvolution_functions, n = 200, standardise = FALSE, scaled = FALSE, cores = 1L, coverage_interval = "wilson", verbose = FALSE, progress_every = 10L )
scenario_config |
Tibble or list of scenario rows. Each row must
contain a |
deconvolution_functions |
Named list passed to
|
n |
Default number of bulk replicates |
standardise, scaled
|
Passed to |
cores |
Workers for the per-sample loop inside
|
coverage_interval |
Coverage interval for the Monte Carlo
coverage rate; see |
verbose |
If |
progress_every |
Sample-progress interval passed to
|
A list with:
regression: global (per-sample composition scores) and
cell_type (across-sample Pearson / F1 / spillover);
monte_carlo: ADEMP summaries per cell type;
optimisation: per-sample elapsed time, memory, KKT residual, and
;
config: tibble of scenario metadata (one row per scenario);
theta_true: list of convolution parameters
(, , )
actually used to draw the bulk;
descriptors: kept scenario statistics (composition, mean, SPD,
network, tangent Fisher, MixSim BarOmega, pairwise Hellinger);
supplementary: Jeffreys overlap, recorded separately;
call: the matched call (match.call()).
Analysis scripts persist those pieces with write_simulation_artefacts()
(scripts/auxiliary/benchmark_artefacts.R) rather than saving the whole
list.
simulate_bulk_mixture(), deconvolute_ratios(),
compute_benchmark_metrics(), describe_simulation_scenario(),
coverage_mc_interval(), plot_mc_raincloud(), plot_mc_forest()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) scenario_config <- tibble::tibble( ID = "B1_Ho", true_theta = list(list( p = c(0.5, 0.5), mu = mu, sigma = Sigma )) ) out <- run_simulation_benchmark( scenario_config = scenario_config, deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 2, cores = 1 ) nrow(out$optimisation)set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) scenario_config <- tibble::tibble( ID = "B1_Ho", true_theta = list(list( p = c(0.5, 0.5), mu = mu, sigma = Sigma )) ) out <- run_simulation_benchmark( scenario_config = scenario_config, deconvolution_functions = list( "nnls" = list(FUN = deconvolute_ratios_nnls) ), n = 2, cores = 1 ) nrow(out$optimisation)
Replaces each by . Then
, so the support of the precision
(structural zeros from the graph) is unchanged.
scale_covariance_array(sigma, scale)scale_covariance_array(sigma, scale)
sigma |
|
scale |
Positive scalar |
Scaled array.
scale_covariances_to_overlap()
sigma <- array(c(diag(2), diag(2)), dim = c(2, 2, 2)) scaled <- scale_covariance_array(sigma, 4) scaled[, , 1]sigma <- array(c(diag(2), diag(2)), dim = c(2, 2, 2)) scaled <- scale_covariance_array(sigma, 4) scaled[, , 1]
Draws cell counts
,
then the exact Gaussian sum of those cells,
,
and scales the total by the platform factor:
.
A sum of independent Gaussian cells is Gaussian, so there is
no per-cell loop.
This is the single-cell mixture (covariance linear in the cell
counts). simulate_bulk_mixture() remains the population-profile
convolution, whose covariance is weighted by .
Pass the cellular moments (generative_mean, generative_sigma
from rescale_single_cell_moments()), not a library-normalised
reference. The returned estimand is the realised cell fraction
.
simulate_bulk_from_cells( mean_signature_matrix, Sigma, p, n_cells, platform_scale = 1, n_samples = NULL, seed = NULL )simulate_bulk_from_cells( mean_signature_matrix, Sigma, p, n_cells, platform_scale = 1, n_samples = NULL, seed = NULL )
mean_signature_matrix |
Per-cell means
|
Sigma |
Per-cell covariances
|
p |
Cell-fraction vector of length |
n_cells |
Cells per bulk sample, |
platform_scale |
Capture scale |
n_samples |
Number of bulk samples when |
seed |
Optional seed, passed to |
A list with Y (), nominal p, realised
p_realised (), counts (),
transcript fractions q, cell_size , platform_scale ,
n_cells , mean_scale and variance_scale
.
simulate_bulk_mixture(),
rescale_single_cell_moments(),
deconvolute_single_cell()
genes <- paste0("g", 1:4) cts <- paste0("ct", 1:2) mu <- matrix( c(2, 2, 0.2, 0.2, 0.2, 0.2, 3, 3), nrow = 4, dimnames = list(genes, cts) ) sigma <- array(0, c(4, 4, 2), dimnames = list(genes, genes, cts)) sigma[,, 1] <- diag(0.05, 4) sigma[,, 2] <- diag(0.05, 4) set.seed(1) sim <- simulate_bulk_from_cells( mu, sigma, p = c(0.8, 0.2), n_cells = 2000, platform_scale = 2, n_samples = 2 ) colSums(sim$counts)genes <- paste0("g", 1:4) cts <- paste0("ct", 1:2) mu <- matrix( c(2, 2, 0.2, 0.2, 0.2, 0.2, 3, 3), nrow = 4, dimnames = list(genes, cts) ) sigma <- array(0, c(4, 4, 2), dimnames = list(genes, genes, cts)) sigma[,, 1] <- diag(0.05, 4) sigma[,, 2] <- diag(0.05, 4) set.seed(1) sim <- simulate_bulk_from_cells( mu, sigma, p = c(0.8, 0.2), n_cells = 2000, platform_scale = 2, n_samples = 2 ) colSums(sim$counts)
For each bootstrap sample , draws latent purified
profiles
independently for each cell type
, then forms the bulk by the linear convolution
matching the article's conditional model
with
.
The mean signature is shared across samples; only the
latent draws vary with . Stacking
those draws into the three-way array
, the bulk
matrix is the mode-2 tensor–vector contraction
which for each sample recovers
with .
simulate_bulk_mixture( signature_matrix, Sigma, p = rep(1/ncol(signature_matrix), ncol(signature_matrix)), n = 500, truncate_negative = FALSE )simulate_bulk_mixture( signature_matrix, Sigma, p = rep(1/ncol(signature_matrix), ncol(signature_matrix)), n = 500, truncate_negative = FALSE )
signature_matrix |
Mean signature
|
Sigma |
Array of covariances
|
p |
Proportion vector |
n |
Number of bulk / bootstrap samples |
truncate_negative |
If |
A list with:
latent_profiles: array
of
unobserved cell-type-specific draws (one slice per
sample );
Y: matrix whose columns
are bulk vectors , obtained as
.
deconvolute_ratios(),
run_simulation_benchmark(),
simulate_bulk_from_cells()
set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) sim <- simulate_bulk_mixture(mu, Sigma, p = c(0.5, 0.5), n = 5) dim(sim$Y)set.seed(1) genes <- paste0("g", 1:2) cts <- paste0("ct", 1:2) mu <- matrix(c(20, 22, 22, 20), nrow = 2, dimnames = list(genes, cts)) Sigma <- array( c(1, 0, 0, 1, 1, 0, 0, 1), dim = c(2, 2, 2), dimnames = list(genes, genes, cts) ) sim <- simulate_bulk_mixture(mu, Sigma, p = c(0.5, 0.5), n = 5) dim(sim$Y)
Builds a mean matrix
and cell-type-specific second-order moments
under a graph-constrained precision model. Means realise a target
Gram matrix via the symmetric square root of
generate_mean_signature_matrix() (equicorrelation by
default, or a full target_gram). For each cell type, an adjacency is drawn from a
random-graph model (or supplied), i.i.d. signed weights with
inhibitory fraction prop_inhibitory form ,
and the precision is completed by a spectral shift. Distinct cell
types receive independent precision draws by default (biology
rarely shares one network across types); pass a length-
graph_model / graph_params or a pre-built
adjacency list / array for hybrid designs.
simulate_hierarchical_grn_moments( n_genes, n_celltypes = 2L, mean_scale = 10, target_cosine = 0, target_gram = NULL, seed = NULL, nonnegative = FALSE, precision_shift, precision_scale, prop_inhibitory = 0.5, graph_model = c("erdos_renyi", "hub", "star", "scale_free", "stochastic_block_model", "small_world"), graph_params = list(), adjacency = NULL )simulate_hierarchical_grn_moments( n_genes, n_celltypes = 2L, mean_scale = 10, target_cosine = 0, target_gram = NULL, seed = NULL, nonnegative = FALSE, precision_shift, precision_scale, prop_inhibitory = 0.5, graph_model = c("erdos_renyi", "hub", "star", "scale_free", "stochastic_block_model", "small_world"), graph_params = list(), adjacency = NULL )
n_genes |
Integer |
n_celltypes |
Integer |
mean_scale |
Positive scalar |
target_cosine |
Numeric pairwise cosine |
target_gram |
Optional symmetric |
seed |
Optional integer. When supplied, the orthonormal frame
|
nonnegative |
If |
precision_shift |
Diagonal cushion |
precision_scale |
Positive magnitude |
prop_inhibitory |
Numeric in |
graph_model |
One of |
graph_params |
Named list of generator parameters (shared), or a
list of length |
adjacency |
Optional pre-built undirected adjacencies: a list of
|
Named list with:
mean_profiles: matrix ;
covariance_matrices: array
;
precision_matrices: array
;
graph_structure: adjacency_matrices, weighted_adjacencies,
and normalised_precision (all );
objectives: mean_abs_cosine and sum_euclidean_distance.
set.seed(42) moments <- simulate_hierarchical_grn_moments( n_genes = 40L, n_celltypes = 3L, mean_scale = 10, target_cosine = 0.1, precision_shift = 0.1, precision_scale = 0.3, prop_inhibitory = 0.5, graph_model = "scale_free" ) str(moments, max.level = 2)set.seed(42) moments <- simulate_hierarchical_grn_moments( n_genes = 40L, n_celltypes = 3L, mean_scale = 10, target_cosine = 0.1, precision_shift = 0.1, precision_scale = 0.3, prop_inhibitory = 0.5, graph_model = "scale_free" ) str(moments, max.level = 2)
Generalised method of moments for the two technical scales, at a
composition that is either supplied or taken from the free-scale
DeconRNASeq start
.
The start is floored into the open simplex. At that composition,
and
,
with .
Then and .
is a cell count only when the two platforms share their
scale; it is not rounded.
is not the library-size ratio
.
single_cell_nuisance_scales(y, mean_signature_matrix, Sigma, p = NULL)single_cell_nuisance_scales(y, mean_signature_matrix, Sigma, p = NULL)
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
p |
Optional composition. |
List with p, ols_scale (the least-squares ,
or NA when p was supplied), mean_scale, variance_scale,
platform_scale and n_cells.
deconvolute_single_cell(),
deconvolute_ratios_deconrnaseq()
mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) set.seed(1) y <- 30 * drop(mu %*% c(0.6, 0.4)) + rnorm(4, sd = 0.5) single_cell_nuisance_scales(y, mu, sigma)mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) set.seed(1) y <- 30 * drop(mu %*% c(0.6, 0.4)) + rnorm(4, sd = 0.5) single_cell_nuisance_scales(y, mu, sigma)
The scenario grid used to check the single-cell fit. Two
compositions, equal and imbalanced, crossed with equal and unequal
cell sizes. Every scenario is drawn at genes,
cells and platform scales
(same capture efficiency, or twice the bulk capture of the
single-cell platform).
single_cell_scenario_design()single_cell_scenario_design()
A list with n_genes, n_cells, platform_scale and
scenarios (four named lists with proportions and cell_size).
rescale_single_cell_moments(),
simulate_bulk_from_cells()
names(single_cell_scenario_design()$scenarios)names(single_cell_scenario_design()$scenarios)
The convolution log-likelihood is not globally concave, so the start
can change which basin the solver enters. Draw several independent
Dirichlet starts (different RNG streams or
multistart_decovart()) rather than a single draw when probing
multimodality.
starting_simplex( n_celltypes, initial_p = NULL, nms = NULL, y = NULL, mean_signature_matrix = NULL, dirichlet_alpha = 1 )starting_simplex( n_celltypes, initial_p = NULL, nms = NULL, y = NULL, mean_signature_matrix = NULL, dirichlet_alpha = 1 )
n_celltypes |
Integer |
initial_p |
One of:
|
nms |
Optional names (cell-type colnames). |
y, mean_signature_matrix
|
Bulk and signature, required for a QP start. |
dirichlet_alpha |
Positive concentration, recycled to length
|
A length- open-simplex vector.
multistart_decovart(), deconvolute_ratios_deconrnaseq()
starting_simplex(3L) set.seed(1) starting_simplex(3L, "dirichlet")starting_simplex(3L) set.seed(1) starting_simplex(3L, "dirichlet")
theme_minimal() plus a panel border and white-on-black facet
strips, after theme_features() in the
atlas-feature-selection-benchmark
plotting helpers.
theme_decovart_facets(base_size = 11, ...)theme_decovart_facets(base_size = 11, ...)
base_size |
Base font size for |
... |
Passed to |
A ggplot2 theme object.
plot_mc_forest(), plot_mc_raincloud()
ggplot2::ggplot(mtcars, ggplot2::aes(wt, mpg)) + ggplot2::geom_point() + ggplot2::facet_wrap(~cyl) + theme_decovart_facets()ggplot2::ggplot(mtcars, ggplot2::aes(wt, mpg)) + ggplot2::geom_point() + ggplot2::facet_wrap(~cyl) + theme_decovart_facets()
Maps the expected Fisher information of unconstrained proportions through the isometric log-ratio (ILR) chart and back to the simplex via the delta method.
Let
with Jacobian
(jacobian_isometric_logistic()). Fisher information transforms as
The first-order delta method then yields
This simplex covariance is invariant to orthogonal rotations of
. The construction is undefined on the simplex
boundary (the log-ratio chart blows up); the function then returns
NA with a warning.
Wald intervals in vcov.decovart_fit(), confint.decovart_fit()
and deconvolute_ratios() all use this expected-Fisher ILR map.
The observed Hessian hessian_loglik_constrained() is for Newton
steps only; it is not the Wald covariance.
vcov_ilr_delta(p, mean_signature_matrix, Sigma, warn = TRUE)vcov_ilr_delta(p, mean_signature_matrix, Sigma, warn = TRUE)
p |
Numeric proportions on the open simplex. |
mean_signature_matrix |
Mean signature |
Sigma |
Cell-type covariances |
warn |
If |
Symmetric asymptotic covariance of
, or a matrix of NA if the bound is
undefined / singular.
expected_fisher_unconstrained(), vcov.decovart_fit(),
confint.decovart_fit(), jacobian_isometric_logistic()
# Two cell types: a single unconstrained ILR coordinate maps back to # a rank-1 covariance on the simplex (rows sum to zero). p <- c(ct1 = 0.6, ct2 = 0.4) mu <- cbind(ct1 = c(0, 0), ct2 = c(3, 0)) Sigma <- array(c(diag(2), diag(2)), dim = c(2, 2, 2)) v <- vcov_ilr_delta(p, mu, Sigma) round(v, 4) abs(rowSums(v)) < 1e-10# Two cell types: a single unconstrained ILR coordinate maps back to # a rank-1 covariance on the simplex (rows sum to zero). p <- c(ct1 = 0.6, ct2 = 0.4) mu <- cbind(ct1 = c(0, 0), ct2 = c(3, 0)) Sigma <- array(c(diag(2), diag(2)), dim = c(2, 2, 2)) v <- vcov_ilr_delta(p, mu, Sigma) round(v, 4) abs(rowSums(v)) < 1e-10
At a fitted composition, the covariance of the ILR coordinate
is the inverse of the negative profile
Hessian hessian_profile_loglik_single_cell_ilr(). The delta method
carries it to with
. The two technical scales use the other Schur
complement of the joint observed Hessian in
: estimating the composition widens
their variances, and is not assumed to make that
complement diagonal.
Both matrices are observed information, not expected Fisher information. They treat the reference moments as known.
vcov_single_cell( p, y, mean_signature_matrix, Sigma, mean_scale = NULL, variance_scale = NULL, scales_known = FALSE, warn = TRUE )vcov_single_cell( p, y, mean_signature_matrix, Sigma, mean_scale = NULL, variance_scale = NULL, scales_known = FALSE, warn = TRUE )
p |
Fitted composition. A boundary coordinate makes the ILR chart undefined. |
y |
Bulk vector of length |
mean_signature_matrix |
Reference mean, |
Sigma |
Cell-level covariances, |
mean_scale, variance_scale
|
Scales at |
scales_known |
If |
warn |
If |
A list with rho, vcov_rho, vcov (delta method for
), mean_scale, variance_scale and
vcov_nuisance (order , ). Singular blocks are
filled with NA.
deconvolute_single_cell(), confint_single_cell()
mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) vcov_single_cell(c(0.7, 0.3), y, mu, sigma)mu <- matrix(c(2, 0.2, 0.2, 2, 0.2, 3, 0.2, 3), nrow = 4) sigma <- array(rep(diag(0.05, 4), 2), c(4, 4, 2)) y <- 20 * drop(mu %*% c(0.7, 0.3)) + c(0.3, -0.2, 0.1, -0.1) vcov_single_cell(c(0.7, 0.3), y, mu, sigma)