| nmf.ffb.inference | R Documentation |
nmf.ffb.inference performs statistical inference on the structural
coefficient matrices C_1 (latent feedback, \Theta_1) and
C_2 (exogenous loading, \Theta_2) from a fitted
nmf.ffb model, after the feed-forward null has been
rejected by nmf.ffb.test. The
basis \hat X is held fixed throughout, which avoids label switching
and gives a clean conditional interpretation: uncertainty of the structural
coefficients given the measurement model. Which resampling scheme is run
depends on object$method.
method = "fiml": a parametric bootstrap from the selected
model. B data sets are drawn from the selected model (with its
\Theta_1) and (\Theta_1, \Theta_2, \Phi, \psi) are re-estimated
with X and the selected support held fixed. Confidence intervals are
the centred (basic) percentile intervals [2\hat\theta -
q^*_{1-\alpha/2},\; 2\hat\theta - q^*_{\alpha/2}]; support_rate is
the share of replicates with |\hat\theta^*| > threshold (0 for
entries outside the selected support), and prob.unsupported is
1 - \mathrm{support\_rate}.
These are post-selection quantities, conditional on the support that
BIC picked, and they can overstate the evidence. They answer "how large is
this entry, given that the procedure kept it", not "is there feedback at
all"; the calibrated statement about the presence of feedback is
nmf.ffb.test, which is the step that belongs before this one.
Each replicate seeds itself (seed + B + b), so the result does not
depend on cores.
method = "mu" (legacy fits, and objects without a
method field). The procedure is a full pair bootstrap that holds the basis
matrix \hat X from the original fit fixed across all replicates
(which avoids label switching and gives a clean conditional
interpretation: “uncertainty of the structural coefficients given the
measurement model”):
For each replicate b = 1, \dots, B, resample column indices
(i_1, \dots, i_N) with replacement from \{1, \dots, N\}
and form Y_1^{(b)} = Y_1[, i], Y_2^{(b)} = Y_2[, i].
Re-estimate (C_1^{(b)}, C_2^{(b)}) by running the
nmf.ffb multiplicative updates with X = \hat X
held fixed (no X update; no centroid sort), using the same
C1.L1, C2.L1 as the original fit.
Discard replicates that violate stationarity
(\rho(X C_1^{(b)}) \ge 1) or have an amplification ratio
exceeding the geometric-series bound by more than 1\
Because C_1, C_2 \ge 0 are non-negative by construction, exact
zeros are essentially never observed in the bootstrap distribution.
Significance is assessed via a support rate at a small display
threshold \delta (default 0.01):
\mathrm{sup}(c) \;=\; \frac{1}{|\mathrm{valid}|}
\sum_{b \in \mathrm{valid}} \mathbf{1}\!\left( \hat c^{(b)} > \delta \right).
This is a one-sided counterpart of the classical p-value:
large support_rate indicates strong evidence that the entry is
meaningfully positive. Significance markers follow the lavaan
convention with the natural correspondence p = 1 - \mathrm{sup}:
* (sup > 0.95), ** (sup > 0.99), ***
(sup > 0.999). Cutoffs use strict greater-than so the rule
mirrors the standard R convention for p-values (p < 0.05 / 0.01 /
0.001 → //), translated to support_rate via
\mathrm{sup} = 1 - p.
nmf.ffb.inference(
object,
Y1,
Y2,
B = 1000L,
threshold = 0.01,
boot.level = 0.95,
C1.L1 = 1,
C2.L1 = 0.1,
seed = 123L,
...
)
object |
A fitted object returned by |
Y1 |
Endogenous variable matrix (P1 x N). Must match the data
used in |
Y2 |
Exogenous variable matrix (P2 x N). Same. |
B |
Number of bootstrap replicates. Default |
threshold |
Display threshold |
boot.level |
Confidence level for the bootstrap CI.
Default |
C1.L1, C2.L1 |
L1 sparsity penalties used by the original
|
seed |
Base RNG seed for the bootstrap. For |
... |
Hidden options. Shared:
|
The input object with additional bootstrap inference
components:
coefficients |
Data frame with rows for every entry of |
C1.support.rate, C2.support.rate |
Per-element support rates (Q x P1 and Q x P2 matrices). |
C1.ci.lower, C1.ci.upper, C2.ci.lower, C2.ci.upper |
Per-element
CI bounds (percentile for |
C1.boot.draws, C2.boot.draws |
Bootstrap distributions: 3D arrays of shape
B x Q x P1 (and B x Q x P2). Invalid replicates contain |
rho.boot.draws |
Per-replicate spectral radius |
AR.boot, iter.boot |
( |
#'
boot.B, boot.threshold, boot.level |
Inputs recorded for reproducibility. |
boot.n.valid, boot.n.invalid |
Validity counts (for |
boot.method |
How the replicates were drawn. |
identified.approx, identification |
Whether |
The calibrated test of the feed-forward null – LR.p.boot,
prob.select.null, C1.restriction.change.rate and the null
bootstrap behind them – is not returned here. It moved to
nmf.ffb.test in 0.9.8, so that an object carrying coefficient
intervals cannot be mistaken for a test of feedback (see NEWS).
This function's interface changed at v0.6.8: the legacy 1-step Newton
wild bootstrap (with sandwich SE) has been replaced by the full pair
bootstrap described above, following the paper revision. The fields
sigma2.used, C2.se, C2.se.boot, C2.p.side
that the previous implementation produced are no longer present.
Satoh, K. (2025). Applying non-negative matrix factorization with covariates to structural equation modeling for blind input-output analysis. arXiv:2512.18250. https://arxiv.org/abs/2512.18250
nmf.ffb, nmf.ffb.DOT
Y <- t(iris[, -5])
Y1 <- Y[1:2, ]; Y2 <- Y[3:4, ]
res <- nmf.ffb(Y1, Y2, rank = 2)
## intervals for the entries the test has already licensed reading.
inf <- nmf.ffb.inference(res, Y1, Y2, B = 20) # use B = 1000 in practice
head(inf$coefficients) # estimate, interval and support rate per entry
res.mu <- nmf.ffb(Y1, Y2, rank = 2, method = "mu")
res.mu2 <- nmf.ffb.inference(res.mu, Y1, Y2, B = 200)
head(res.mu2$coefficients)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.