nmfkc.inference performs statistical inference on the parameter matrix
\(C\) (\(\Theta\)) from a fitted nmfkc model, conditional on
the estimated basis matrix \(\hat{X}\).
Under the working model \(Y = X C A + \varepsilon\) where \(\varepsilon_{pn} \stackrel{iid}{\sim} N(0, \sigma^2)\), inference is conducted via sandwich covariance estimation and one-step wild bootstrap with non-negative projection.
Arguments
- object
An object of class
"nmfkc"returned bynmfkc.- Y
Observation matrix (P x N). Must match the data used in
nmfkc().- A
Covariate matrix (K x N). Default is
NULL(same as identity; in this case \(B = C\) and inference is on \(B\) directly).- wild.bootstrap
Logical. If
TRUE(default), performs wild bootstrap for confidence intervals and bootstrap standard errors. Set toFALSEto skip bootstrap (faster, only sandwich SE is computed).- ...
Additional arguments:
methodBootstrap engine.
"onestep"(default): a one-step Newton linearisation around the fit using the inverse informationHinv(fast; the sandwich SE is primary)."refit": a residual wild bootstrap that re-estimates \(C\) to convergence with the basis \(X\) held FIXED. The "refit" engine uses no information matrix, so it stays valid when the Fisher information \(AA'\) is singular (over-parameterised covariates) or \(C\) sits on the \(\ge 0\) boundary; the bootstrap SE/CI become primary and the p-value is a two-sided bootstrap p-value.wild.distMultiplier distribution (orthogonal to
method):"rademacher"(\(\pm 1\)),"mammen"(Mammen 1993 two-point), or"exp"(\(\mathrm{Exp}(1)-1\)). Default"exp"formethod="onestep"(backward compatible),"rademacher"for"refit".wild.unitFor
method="refit":"element"(default, i.i.d. multiplier per matrix cell) or"column"(one multiplier per sample column, shared over rows).refit.epsilon,refit.maxitFor
method="refit": convergence tolerance and iteration cap of the re-fits, defaulting to1e-8and100000. These are deliberately far tighter thannmfkc's own1e-4: under multiplicative updates a coefficient heading for the non-negativity boundary approaches 0 slowly, so at a loose tolerance every replicate stops while that coefficient is still spuriously positive. The replicates then pile up above the point estimate, the percentile interval can exclude it entirely, and the bootstrap SE is understated. Loosen only if the re-fits are too slow, and check that the intervals still contain the estimates.wild.BNumber of bootstrap replicates. Default is 500.
wild.seedSeed for bootstrap. Default is 42.
wild.levelConfidence level for bootstrap CI. Default is 0.95.
sandwichLogical. Use sandwich covariance. Default is
TRUE.C.p.sideP-value type:
"one.sided"(default) or"two.sided".cov.ridgeRidge stabilization for information matrix inversion. Default is 1e-8.
print.traceLogical. If
TRUE, prints progress. Default isFALSE.
Value
An object of class c("nmfkc.inference", "nmfkc"), inheriting all
components from the input object, with additional inference components:
- sigma2.used
Estimated \(\sigma^2\) used for inference.
- C.se
Sandwich standard errors for \(C\) (Q x K matrix).
- C.se.boot
Bootstrap standard errors for \(C\) (Q x K matrix).
- C.ci.lower
Lower CI bounds for \(C\) (Q x K matrix).
- C.ci.upper
Upper CI bounds for \(C\) (Q x K matrix).
- coefficients
Data frame with one row per element of \(C\).
SEis always the sandwich standard error andBSEalways the bootstrap one, so the two columns differ;z_valueandp_valueuse whichever is primary for the chosenmethod(bootstrap under"refit", sandwich under"onestep").on.boundaryflags coefficients at or belowboundary.tol(default1e-3): their interval and p-value behave correctly in the "do not reject" direction, but the value is not a calibrated p-value — a one-sided bootstrap p piles up near \(1/2\) at the boundary.- C.p.side
P-value type used.
References
Satoh, K. (2026). Wild Bootstrap Inference for Non-Negative Matrix Factorization with Random Effects. arXiv:2603.01468. https://arxiv.org/abs/2603.01468
Examples
Y <- matrix(cars$dist, nrow = 1)
A <- rbind(intercept = 1, speed = cars$speed)
result <- nmfkc(Y, A, rank = 1)
#> Y(1,50)~X(1,1)C(1,2)A(2,50)=XB(1,50)...
#> 0sec
result2 <- nmfkc.inference(result, Y, A)
summary(result2)
#>
#> Call:
#> nmfkc(Y = Y, A = A, rank = 1)
#>
#> Dimensions: Y(1,50)~X(1,1)C(1,2)A(2,50)=XB(1,50)
#> Rank (Q): 1
#> Runtime: 0.0sec
#> Method: EU
#> Iterations: 67 / 5000 (converged) epsilon = 0.0001 last change = 9.8e-05
#> Missing: 0 (0.0%)
#>
#> Statistics:
#> Objective function: 12982
#> R-squared (cor^2): 0.6511
#> R-squared (uncentered): 0.8961
#> R-squared (centered): 0.601
#> Residual Std Error: 16.17
#> Mean Absolute Error: 12.71
#>
#> Structure Diagnostics:
#> Basis (X) Sparsity: 0.0% (< 1e-4)
#> Coef (B) Sparsity: 0.0% (< 1e-4)
#>
#> Inference (conditional on X):
#> sigma^2: 270.5
#>
#> Coefficients (conditional on X): 2 total, 1 significant
#> Cov:Basis Estimate Std. Error (Boot) z value Pr(>z)
#> intercept:Basis1 0.156 6.512 3.351 0.02 0.4904
#> speed:Basis1 2.900 0.464 0.439 6.25 2.102e-10 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>