Maximum-likelihood estimator of cellular proportions
\(\boldsymbol{p}_{\cdot i}\) under the multivariate Gaussian convolution
$$
\boldsymbol{y}_{\cdot i}\mid(\boldsymbol{\mu},\boldsymbol{\Sigma}_j,
\boldsymbol{p}_{\cdot i})
\sim
\mathcal{N}_{G}\bigl(
\boldsymbol{\mu}\boldsymbol{p}_{\cdot i},\;
\boldsymbol{\Sigma}(\boldsymbol{p}_{\cdot i})
\bigr),
\qquad
\boldsymbol{\Sigma}(\boldsymbol{p})
=\sum_{j=1}^{J}p_j^{2}\boldsymbol{\Sigma}_j.
$$
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 \(\boldsymbol{\mu}\). 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
\(\boldsymbol{Y}-\boldsymbol{\mu}\hat{\boldsymbol{P}}\); they are not OLS
residuals. Goodness of fit is the convolution log-likelihood, not
residual sum of squares.
Usage
fit_decovart(
signature_matrix,
bulk_expression,
true_ratios = NULL,
Sigma = NULL,
method = c("Marquardt-Levenberg", "L-BFGS-B", "Newton-Raphson"),
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, ...)Arguments
- signature_matrix
Mean signature \(\boldsymbol{\mu}\in\mathcal{M}_{G\times J}\) (rownames = genes, colnames = cell types).
- bulk_expression
Bulk matrix \(\boldsymbol{Y}\in\mathcal{M}_{G\times N}\) (rownames = genes, colnames = samples).
- true_ratios
Optional ground-truth proportions (\(J\) vector or \(J\times N\) matrix). Stored on the fit; not used by the MLE.
- Sigma
Array \((\boldsymbol{\Sigma}_j)_{j}\in\mathcal{M}_{G\times G\times J}\) of cell-type covariances.
- method
Optimiser; one of
"Marquardt-Levenberg","L-BFGS-B","Newton-Raphson"(case-insensitive). These three maps already land on the simplex (ILR or \(p/\sum p\)); they do not callrepair_simplex().- epsilon, itmax
Absolute convergence tolerance and iteration budget, in the same roles as
reltol/maxitinstats::optim().- standardise
If
TRUE, apply a gene-wise affine z-score computed once from \(\boldsymbol{\mu}\) to bulk, means and covariances (see Details). Cell-type-wise or sample-wise transforms are not supported.- scaled
Deprecated.
TRUE(log2 mixing) always errors.- n_starts
Number of additional random Dirichlet starts per sample. With
n_starts > 0the best log-likelihood is kept andmultistart_decovart()records the spread of attained optima, the only direct probe of multimodality (the realised log-likelihood is not globally concave).- boundary_tol
Threshold on \(\min_j\hat{p}_j\) below which a sample is flagged
near_boundarybyboundary_diagnostics(). Wald intervals are unreliable there; preferconfint_profile_decovart()orlrt_decovart().- x, object
A
decovart_fit.- ...
Passed to
graphics::plot()(plot method) or ignored.- parm
Kept for compatibility with
stats::confint(); all simplex coordinates are always returned (subsetting byparmis not implemented). Removing this formal would break the S3 method contract with the generic.- level
Confidence level \(1-\alpha\) (default
0.95). Wald intervals use asymptotic normality of the MLE with standard errors fromvcov_ilr_delta()/expected_fisher_unconstrained()(see Details offit_decovart()and ofvcov_ilr_delta()): \(\hat{p}_j \pm z_{1-\alpha/2}\,\mathrm{SE}_j\).
Details
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 \(\log(\boldsymbol{\mu}\boldsymbol{p})\neq(\log\boldsymbol{\mu})\boldsymbol{p}\). A gene-wise affine map \(\boldsymbol{x}\mapsto D^{-1}(\boldsymbol{x}-\boldsymbol{m})\) with the same \(D,\boldsymbol{m}\) on \(\boldsymbol{Y}\), \(\boldsymbol{\mu}\) and \(\boldsymbol{\Sigma}_j^\star=D^{-1}\boldsymbol{\Sigma}_j D^{-1}\) leaves the MLE of \(\boldsymbol{p}\) unchanged (equivariance).
Wald covariance. Let
\(\boldsymbol{\Omega}(\boldsymbol{p})=\boldsymbol{\Sigma}(\boldsymbol{p})^{-1}\).
The expected Fisher information of the unconstrained mean–covariance
map (multivariate normal; see e.g. the Wikipedia entry Fisher
information, multivariate normal) is
$$
I(\boldsymbol{p})_{jk}
=
\boldsymbol{\mu}_{\cdot j}^{\top}
\boldsymbol{\Omega}(\boldsymbol{p})
\boldsymbol{\mu}_{\cdot k}
+
2 p_j p_k\,
\mathrm{tr}\bigl(
\boldsymbol{\Omega}(\boldsymbol{p})\boldsymbol{\Sigma}_j
\boldsymbol{\Omega}(\boldsymbol{p})\boldsymbol{\Sigma}_k
\bigr).
$$
Cramer–Rao gives
\(\mathrm{Var}(\hat{\boldsymbol{z}})\succeq I_{\boldsymbol{z}}^{-1}\)
in ILR coordinates, with
\(I_{\boldsymbol{z}}
=\mathbf{J}_{\boldsymbol{\psi}}^{\top} I(\boldsymbol{p})
\mathbf{J}_{\boldsymbol{\psi}}\) and
\(\mathbf{J}_{\boldsymbol{\psi}}
=\mathbf{S}(\boldsymbol{p})\mathbf{V}\)
(jacobian_isometric_logistic()). The delta method maps the bound
back to the simplex:
$$
\mathrm{Var}(\hat{\boldsymbol{p}})
=
\mathbf{J}_{\boldsymbol{\psi}}
I_{\boldsymbol{z}}^{-1}
\mathbf{J}_{\boldsymbol{\psi}}^{\mathsf{T}}.
$$
References
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 .
See also
deconvolute_ratios(),
deconvolute_ratios_Marquardt_Levenberg(),
expected_fisher_unconstrained(), vcov_ilr_delta(),
coef.decovart_fit(), vcov.decovart_fit(),
confint.decovart_fit()
Examples
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)
#> sample_1 sample_2
#> ct1 0.4461301 0.7062033
#> ct2 0.5538699 0.2937967
nobs(fit)
#> [1] 2
#> attr(,"n_genes")
#> [1] 2
#> attr(,"n_celltypes")
#> [1] 2
#> attr(,"n_samples")
#> [1] 2