Fit per-feature KDE naive-Bayes class-conditional LRT discriminator
Source:R/singlesample-nbkde-scorers.R
fit_lrt_nbkde.RdLearns a frozen two-class discriminator from training data using a per-feature kernel density estimate (KDE) of each class-conditional marginal under a naive-Bayes (feature-independence) assumption. Each specimen is first mapped to a self-contained, per-sample robust centred-log-ratio (rCLR) representation \(z\), where \(z_j = \log v_j - \mathrm{mean}_{k:\,v_k>0}\log v_k\) on the nonzero parts of the specimen and \(z_j = 0\) on its zero parts. Because the centring uses only that specimen's own nonzero values, \(z(c\,v) = z(v)\) for any \(c>0\): the representation – and therefore every downstream score – is exactly invariant to per-sample scaling (library size / input amount).
This is the marginal complement to the Gaussian-copula LRT. The copula
matches out the per-feature marginals via a probability-integral transform and
scores only the residual feature dependence; lrt-nbkde does the
opposite – it scores the per-feature class-conditional marginal density
ratio and ignores dependence (the naive-Bayes assumption). For each feature
\(j\) and class \(c \in \{\mathrm{case}, \mathrm{control}\}\) the frozen
marginal is a Gaussian-kernel KDE of the training rCLR values
\(z^{\mathrm{train}}_{c,j}\):
$$\log f_{c,j}(t) = \mathrm{logSumExp}_{i}\!\left(
-\tfrac{1}{2}\Big(\tfrac{t - z^{\mathrm{train}}_{c,j,i}}{h_j}\Big)^2\right)
- \log n_{c} - \log h_j - \tfrac{1}{2}\log(2\pi),$$
evaluated directly at the specimen's own coordinate \(t = z_j\) (not on a
fixed grid), so it is exact and computable from a single specimen.
The per-feature bandwidth \(h_j\) is frozen at fit. By default it is the
Silverman rule-of-thumb stats::bw.nrd0 of the pooled rCLR values
of feature \(j\) across both classes (so the case and control
marginals of a feature are smoothed comparably), scaled by hp$bw_adjust
and floored at hp$eps: \(h_j = \max(\mathrm{adjust}\cdot
\mathrm{bw.nrd0}(\mathrm{pool}_j),\, \epsilon)\). If hp$bw is supplied,
that positive scalar replaces bw.nrd0 for every feature.
Fitting stores the raw case/control anchor rows (so the per-feature KDEs can be re-derived consistently over any present-feature subset at scoring), the frozen training feature universe, the resolved hyperparameters, and – for inspection and tests – the full-universe class representation (per-class rCLR anchor values and the per-feature bandwidths). No test data and no test-time batch statistic are used.
Usage
fit_lrt_nbkde(X_train, y_train, meta_train = NULL, hp = list())Arguments
- X_train
Numeric matrix (samples \(\times\) features) of non-negative abundance values. Columns must be uniquely named feature ids.
- y_train
Integer/numeric 0/1 labels aligned to
X_train; 1 is case/disease and 0 is control.- meta_train
Optional per-sample metadata. Accepted for interface uniformity and ignored by this method.
- hp
List of frozen hyperparameters:
bweitherNULL(default; the per-feature pooledstats::bw.nrd0bandwidth is used) or a single positive finite scalar bandwidth applied to every feature;bw_adjustpositive finite multiplier on the bandwidth analogous todensity(adjust=)(default1.0);max_anchors_per_classpositive-integer anchor cap per class (default200L);min_featurespositive-integer feature-overlap floor at scoring (default3L);epspositive bandwidth/density floor (default1e-6); andseednon-negative integer used only for deterministic anchor subsampling while restoring the global RNG state (default1L).
Value
A plain list of class lrt_nbkde_model containing
case_anchors, control_anchors, feature_universe,
repr (the full-universe frozen class representation: z_case,
z_control, and the per-feature bw), and the resolved hp.
Details
The single-specimen score (see score_lrt_nbkde) is the naive-Bayes
class-conditional marginal log-likelihood ratio
$$S(z) = \sum_{j} \big[\log f_{\mathrm{case},j}(z_j)
- \log f_{\mathrm{control},j}(z_j)\big],$$
a sum of per-feature class-conditional marginal log-density ratios; larger
means more case-like. The bandwidth and the \(-\tfrac12\log(2\pi)\) constant
cancel within each feature's ratio, so only the kernel sums and the per-class
log-counts \(\log n_c\) survive.
Degenerate features are handled without any caller-side special-casing. A
feature that is constant across a class's training anchors (e.g. zero in all of
them) still yields a finite KDE: the pooled bw.nrd0 stays positive (it
falls back to a unit scale for a constant input) and is in any case floored at
hp$eps, and the Gaussian kernel sum is evaluated through a stable
log-sum-exp so each \(\log f_{c,j}\) is finite. The fit and every score
therefore remain finite.
References
Silverman B.W. (1986) Density Estimation for Statistics and Data Analysis. Chapman and Hall, London.
Scott D.W. (1992) Multivariate Density Estimation: Theory, Practice, and Visualization. Wiley, New York.
Hand D.J., Yu K. (2001) Idiot's Bayes – not so stupid after all? International Statistical Review 69(3): 385-398.
Examples
if (FALSE) { # \dontrun{
set.seed(1)
n <- 120; p <- 30
L <- matrix(stats::rnorm(n * p, 4, 0.6), nrow = n,
dimnames = list(NULL, paste0("miR-", seq_len(p))))
y <- rep(c(0, 1), each = n / 2)
L[y == 1, 1:8] <- L[y == 1, 1:8] + 1.2 # case-only marginal location shift
X <- exp(L)
model <- fit_lrt_nbkde(X, y)
score <- score_lrt_nbkde(model, X)
} # }