The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
A dynamic missingness graph (dm-graph) is a directed acyclic graph over the unrolled within-person process of an experience-sampling study. It extends the missingness graphs of Mohan and Pearl (2021) to repeated prompts: instead of one node per variable, the graph has one node per variable and prompt, and the missingness mechanism is a set of edges into the response indicators.
The nodes are
eta, the person’s typical state (a person-level latent
variable; in estimation it is realized by person-specific
intercepts);X1, X2, ..., the momentary states at prompts 1, 2, …;
the third prompt of the window is the focal prompt t, so
X3 is Xt, X2 is
Xt-1, and so on;R1, R2, ..., the response indicators (1 = the prompt
was answered, and the states are recorded);C (a context variable, latent or observed),
S (an always-observed passive sensor), Z (a
randomized probe that forces a response), zeta (a
person-level response propensity) and U (a latent common
cause of eta and zeta).Two kinds of edges are always present: the dynamics
X_{t-1} -> X_t and the person effect
eta -> X_t. Everything else is a declaration about
why prompts are skipped.
Each motif adds a specific set of edges. The codes are the ones used
throughout the package (in dm_graph(),
simulate_ema() and the printed reports).
| Code | Name | Edges added | Substantive story |
|---|---|---|---|
| M0 | completely random | none into R |
a phone left in another room |
| M1 | lagged-state dependence | X_{t-1} -> R_t |
high stress in the morning predicts skipping the afternoon prompt |
| M2 | self-censoring | X_t -> R_t |
the current state itself causes the skip: too anxious to answer right now |
| M3 | burden or fatigue | R_{t-1} -> R_t |
having skipped once makes skipping again more likely; compliance declines |
| M4 | person propensity | zeta -> R_t, U -> eta,
U -> zeta |
some people respond less, and they also differ in their typical states |
| M5 | context confounding | C_t -> X_t, C_t -> R_t |
being at work raises stress and lowers responding |
| M6 | reactivity | R_{t-1} -> X_t |
answering a prompt changes the next state (assessment reactivity) |
The plots below draw each motif. Structural edges are gray and solid, motif edges are black and dashed, latent nodes are open circles.
Motifs combine. dm_graph(c("M2", "M4")) declares
self-censoring together with a person propensity;
dm_graph(c("M1", "M3")) declares lagged-state dependence
together with burden. A context is declared through
context = "latent" or context = "observed"
(which adds M5 automatically), and
context_persistent = TRUE adds
C_{t-1} -> C_t. Sensors and probes are design features
rather than mechanisms and are declared through
sensor = TRUE and probe = TRUE.
g <- dm_graph(c("M2", "M4"), sensor = TRUE, probe = TRUE)
g
#> Dynamic missingness graph (window of 5 prompts)
#> motifs: M2 + M4
#> context: none
#> sensor: TRUE probe: TRUE
#> nodes: 23 edges: 31
plot(g)dsep() answers whether two sets of nodes are d-separated
given a conditioning set, with the Bayes-ball algorithm (Shachter, 1998;
Koller & Friedman, 2009). The central question for the transition
kernel is whether the response indicator at t is independent of
the state at t given the previous state and the person:
dsep(dm_graph("M1"), "R3", "X3", c("X2", "eta")) # lagged-state dependence: yes
#> [1] TRUE
dsep(dm_graph("M2"), "R3", "X3", c("X2", "eta")) # self-censoring: no
#> [1] FALSE
dsep(dm_graph("M4"), "R3", "X3", c("X2", "eta")) # the person intercept blocks zeta -> R and U -> eta
#> [1] TRUE
dsep(dm_graph("M4"), "R3", "X3", "X2") # without it, R and X are associated through U
#> [1] FALSEdsep() works on any edge list, not only on dm-graphs,
which makes it easy to check textbook cases:
chain <- list(nodes = c("A", "B", "C"), edges = cbind(from = c("A", "B"), to = c("B", "C")))
c(marginal = dsep(chain, "A", "C"), given_B = dsep(chain, "A", "C", "B"))
#> marginal given_B
#> FALSE TRUE
collider <- list(nodes = c("A", "B", "C"), edges = cbind(from = c("A", "C"), to = c("B", "B")))
c(marginal = dsep(collider, "A", "C"), given_B = dsep(collider, "A", "C", "B"))
#> marginal given_B
#> TRUE FALSErecoverability() applies the d-separation conditions
derived in Yu (2026) to a declared graph and reports, for every estimand
of the two-level VAR(1), whether it is structurally recoverable from the
answered prompts and by which estimator. Recoverability is used in the
sense of Mohan and Pearl (2021): there exists a consistent estimator
that uses only the observed part of the data.
recoverability(dm_graph("M1"))
#> Recoverability report for motifs: M1
#>
#> * transition kernel (Phi, Psi, contemporaneous network)
#> [recoverable] complete adjacent pairs, within-person (person intercepts)
#> condition: R_t _||_ X_t | {X_{t-1},eta} and R_{t-1} _||_ X_t | {X_{t-1},eta, R_t}
#> * person mean via observed within-person mean
#> [NOT recoverable] biased
#> condition: R_t _||_ X_t | {eta}
#> * person mean via recovered dynamics
#> [recoverable] mu_i = (I - Phi)^{-1} c_i from the recovered kernel
#> condition: transition kernel recoverable
#> * between-person law (mu, Sigma_mu), person-weighted
#> [recoverable] one recovered mean per person (dynamics-recovered means), persons weighted equally; positivity assumed
#> condition: a person-mean estimator is available and P(R_t = 1 | eta) > 0
#> * between-person law, prompt-weighted (pooling answered prompts)
#> [NOT recoverable] biased: response rate depends on the person's states
#> condition: R_t _||_ X_t | {empty set}
#> * silence test (coefficient of R_t in X_{t+1} ~ X_{t-1} + R_t, within person)
#> null expected (test valid as a test of the recoverable class)
#> condition: R_t _||_ X_{t+1} | {X_{t-1},eta,R_{t-1},R_{t+1}}The estimands are
R_t is independent of
X_t given X_{t-1} and the person, and
R_{t-1} is independent of X_t given the same
set plus R_t;R_t is independent of X_t given
the person;mu_i = (I - Phi)^{-1} c_i, available whenever the kernel is
recoverable and there is no reactivity;R_t independent of
X_t marginally; andThe loop below reproduces the recoverability table of the accompanying article for all single motifs and the combinations that matter in practice.
decls <- list("M0", "M1", "M2", "M3", "M4", "M5", "M6", c("M1", "M3"), c("M1", "M4"),
c("M3", "M4"), c("M2", "M4"), c("M2", "M3"))
tab <- do.call(rbind, lapply(decls, function(m) {
r <- recoverability(dm_graph(m))
data.frame(motifs = paste(m, collapse = "+"),
kernel = r$recoverable[1], mean_obs = r$recoverable[2], mean_dyn = r$recoverable[3],
law_person = r$recoverable[4], law_prompt = r$recoverable[5],
silence_null = attr(r, "silence_null"))
}))
#> M5 declared without 'context': a latent context is assumed
tab
#> motifs kernel mean_obs mean_dyn law_person law_prompt silence_null
#> 1 M0 TRUE TRUE TRUE TRUE TRUE TRUE
#> 2 M1 TRUE FALSE TRUE TRUE FALSE TRUE
#> 3 M2 FALSE FALSE FALSE FALSE FALSE FALSE
#> 4 M3 TRUE TRUE TRUE TRUE TRUE TRUE
#> 5 M4 TRUE TRUE TRUE TRUE FALSE TRUE
#> 6 M5 FALSE FALSE FALSE FALSE FALSE FALSE
#> 7 M6 TRUE TRUE FALSE TRUE TRUE FALSE
#> 8 M1+M3 TRUE FALSE TRUE TRUE FALSE FALSE
#> 9 M1+M4 TRUE FALSE TRUE TRUE FALSE TRUE
#> 10 M3+M4 TRUE TRUE TRUE TRUE FALSE TRUE
#> 11 M2+M4 FALSE FALSE FALSE FALSE FALSE FALSE
#> 12 M2+M3 FALSE FALSE FALSE FALSE FALSE FALSEThree patterns organize the table.
zeta.R_t depend on
X_t itself, and no conditioning set of observed variables
blocks the path. Structural non-recoverability does not say how large
the bias of a given estimator is: in the additive simulations of Yu
(2026) the lagged coefficients are barely affected by a serially
independent latent context (the shift lands in the intercepts) but are
biased under a persistent one, while the means are biased in both cases,
and under self-censoring everything is biased. This is where the
sensitivity analysis of vignette("sensitivity-analysis")
comes in.The silence_null column shows where the silence test is
a valid test of the recoverable class: everywhere among M0, M1, M3, M4
and their combinations except M1 + M3 (under M6 the kernel is
recoverable, but reactivity makes the test reject by construction),
where conditioning on an answered prompt at t + 1 opens a
collider at R_{t+1}: its parents are R_t
(burden) and X_t (lagged-state dependence), and
X_t drives X_{t+1}. The report says so in
words:
An observed context turns latent M5 into a recoverable mechanism: the
context enters the conditioning set (covariate adjustment,
fit_pairs(covariates = )), or the pairs are reweighted so
that the context-marginal kernel is recovered
(fit_ipw()).
recoverability(dm_graph("M5", context = "observed"))[1, c("recoverable", "estimator")]
#> recoverable
#> 1 TRUE
#> estimator
#> 1 complete pairs, context-conditional kernel (covariate adjustment); context-marginal kernel by stabilized IPW on CA sensor adds the sensor-gap row, which is valid also under M1 + M3 because nothing is conditioned on at t + 1:
rs <- recoverability(dm_graph(c("M1", "M3"), sensor = TRUE))
rs$estimator[grepl("sensor", rs$estimand)]
#> [1] "null expected (test valid as a test of the recoverable class)"A probe adds a row for the kernel estimated from probe prompts only.
Because Z_t = 1 forces R_t = 1, complete pairs
restricted to probe prompts are not selected on X_t even
under self-censoring; this is what
calibrate_delta(method = "probe") exploits.
The graph is a declaration, not a finding: it records what
the analyst is willing to assume about why prompts were skipped, and
recoverability() says what follows. A workable procedure
is
fit_pairs() and run the tests of
vignette("testing-informativeness") as checks; if not, run
the sensitivity analysis;missingness_declaration().Koller, D., & Friedman, N. (2009). Probabilistic graphical models: Principles and techniques. MIT Press.
Mohan, K., & Pearl, J. (2021). Graphical models for processing missing data. Journal of the American Statistical Association, 116, 1023-1037. https://doi.org/10.1080/01621459.2021.1874961
Shachter, R. D. (1998). Bayes-ball: The rational pastime. In Proceedings of the Fourteenth Conference on Uncertainty in Artificial Intelligence (pp. 480-487). Morgan Kaufmann.
Yu, H.-T. (2026). What skipped prompts hide: Detecting, diagnosing, and correcting informative nonresponse in ecological momentary assessment. Manuscript under review.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.