Constructs the neighbourhood-interaction design matrix for a single niche
bandwidth and tags each covariate by type ("CellType", "Niche", "Response",
"ResponseNiche", or "Other"). The scientifically important covariates are the
three-way CellType:condition:niche interactions ("ResponseNiche"), which
capture how expression within an index cell type changes with the condition
as a function of a niche cell type's local density. Self interactions — an
index cell type against its own niche density — are dropped; when niches have
been merged with mergeNiches(), this extends to any index that is a member
of the merged niche's group. This is an escape hatch for custom fits; most
users should call fitSpiDE().
Arguments
- spe
a SpatialExperiment with a niche reducedDim for
sigma.- condition
a character, the colData column of the tested condition, or
NULL(default) for a condition-free design. WithNULLthe condition terms are omitted and the two-wayCellType:nicheinteractions (tagged "Niche") become the tested effects; noResponsecolumns are produced.- sigma
a numeric, the bandwidth (a single value).
- index, niche
character vectors restricting index / niche cell types (NULL = all).
- covariates
a character vector of nuisance colData columns.
- cell_type
a character, the colData column of cell type labels.
- name
a character, the niche reducedDim prefix.
- sample_id
a character, the colData column identifying samples (patients); used only when
random != "none".- random
one of "none" (the default), "intercept" (add a per-sample random intercept) or "slope" (also add per-sample random slopes on the niche covariates). The random-effect columns are penalised at fit time to implement a mixed model via ridge (see the vignette).
This defaults to "none" even though
fitSpiDE()defaults to "intercept". The asymmetry is deliberate: the random-effect columns are collinear with the cell-type block and are identified only by the penalty applied at fit time, so a design returned with them included is rank-deficient. That is correct for fitting and surprising for a constructor whose job is to hand back a design matrix to inspect.- re.celltype
logical; add a nested (sample x cell type) random intercept alongside the per-sample one, so that every tested niche slope is a within-(sample, cell type) slope. Without it the slopes also carry the between-sample composition effect (a patient-level association between a cell type's mean niche density and its mean expression in that type), which is not neighbourhood-dependent differential expression. Ignored when
random = "none". Defaults toFALSEhere andTRUEinfitSpiDE(), for the same reasonrandomdoes: a design returned with penalty-identified columns is rank-deficient, which is correct for fitting and surprising from a constructor.- ...
ignored.
Value
a list with W (the design matrix), covtype (a factor of column
types), coefmap (a data.frame mapping columns to index/niche cells), and
mode ("condition" or "niche").
Details
With condition = NULL the condition terms are omitted and the two-way
CellType:niche interactions ("Niche") become the tested effects. That
design also omits the bare niche main effects, so the interaction block is
cell-means coded: each coefficient is directly the slope of expression on
that niche cell type's log density within the index cell type, rather than
a contrast against a reference cell type.
Examples
data(toySpiDE)
spe <- toySpiDE
spe <- buildNiches(spe, sigma = 20)
des <- nicheDesign(spe, condition = "condition", sigma = 20)
table(des$covtype)
#>
#> CellType Niche Response ResponseNiche
#> 3 4 0 6
#> ResponseCellType Other
#> 3 3
des0 <- nicheDesign(spe, condition = NULL, sigma = 20)
table(des0$covtype)
#>
#> CellType Niche Response ResponseNiche
#> 3 6 0 0
#> ResponseCellType Other
#> 0 0