Skip to contents

Regresses the state at prompt \(t+1\) on the state at \(t-1\) and the response indicator at \(t\), within person, using all triples in which prompts \(t-1\) and \(t+1\) were answered (prompt \(t\) may or may not have been). Under every combination of the recoverable motifs (M0, M1, M3, M4) that does not contain both M1 and M3, \(R_t\) is conditionally independent of \(X_{t+1}\) given \(X_{t-1}\) and the person (Yu, 2026), so the population coefficient of \(R_t\) is zero when the conditional mean of \(X_{t+1}\) given \(X_{t-1}\) is linear (exactly under M0, M3 and M4; under M1 the selection on \(X_t\) through \(R_{t+1}\) makes it slightly nonlinear, and poly = 2 adds squared lagged states to absorb the curvature). Under self-censoring (M2), latent context (M5) or reactivity (M6) the coefficient is not zero. When burden (M3) is combined with a state-dependent motif (M1 + M3, M2 + M3), the conditioning on \(R_{t+1} = 1\) opens a collider at \(R_{t+1}\), whose parents are \(R_t\) (burden) and either \(X_t\) (under M1, and \(X_t\) drives \(X_{t+1}\)) or \(X_{t+1}\) itself (under M2): under M1 + M3 the test rejects in large samples although the kernel is recoverable (with a coefficient of the opposite sign to the self-censoring signature), and under M2 + M3 the collider works against the self-censoring signal and the test loses power. The sign of the coefficient on the self-censoring variable is the sign of the tilt: a negative value means that the states hidden by skips were higher than the states that were reported.

Usage

silence_test(
  data,
  vars,
  id = "id",
  time = "time",
  day = NULL,
  R = "R",
  se = NULL,
  B = 500,
  poly = 1L,
  seed = NULL
)

Arguments

data

Long data frame with one row per scheduled prompt.

vars

Names of the state columns.

id, time

Names of the person and prompt-index columns.

day

Optional name of a day column; pairs are formed only within a day (the overnight gap is not a lag-1 transition).

R

Name of the response-indicator column (0/1, no NA). If the default name is not among the columns of data, a prompt counts as answered when all vars are non-missing; any other name must exist.

se

"cluster" (cluster-robust by person with \(t(G-1)\) and \(F(q, G-1)\) reference distributions; the default when there are at least 10 persons) or "dayblock" (block bootstrap that resamples person-day blocks with replacement; the default with fewer than 10 persons; requires day).

B

Number of bootstrap resamples for se = "dayblock".

poly

Degree of the polynomial in the lagged states (1 = linear).

seed

Optional seed for the bootstrap (the caller's random-number state is restored).

Value

An object of class c("silence_test", "data.frame"): a data frame with one row per state variable and the columns variable,

coef_R (coefficient of \(R_t\)), se, z (the ratio of the coefficient to its standard error, referred to \(t(G - 1)\) under

se = "cluster") and p, and the attributes joint (a named vector with the Wald statistic over all variables, its degrees of freedom and its p value),

n_triples, n_skipped (triples with a skipped middle prompt) and se (the method used). It has a print method.

References

Cameron, A. C., & Miller, D. L. (2015). A practitioner's guide to cluster-robust inference. Journal of Human Resources, 50, 317-372. doi:10.3368/jhr.50.2.317

Yu, H.-T. (2026). What skipped prompts hide: Detecting, diagnosing, and correcting informative nonresponse in ecological momentary assessment. Manuscript under review.

See also

sensor_gap_test, fatigue_check, recoverability (which reports whether the null is expected under a declared graph)

Examples

sim <- simulate_ema(N = 40, n_prompts = 30, motifs = "M2", delta = -1, seed = 1)
st <- silence_test(sim$data, sim$vars)
st
#> Silence test: X_{t+1} ~ X_{t-1} + R_t (within person), 660 triples, 97 with a skipped middle prompt
#>  variable coef_R    se     z       p
#>      NegA -0.546 0.106 -5.16 8.1e-06
#>      PosA  0.089 0.109  0.82 4.2e-01
#>    Stress -0.391 0.101 -3.86 4.3e-04
#>   Fatigue -0.133 0.130 -1.02 3.1e-01
#> Joint Wald test: statistic = 34.77 on 4 df, p = 4.39e-05   [SE: cluster; t / F with G - 1 df reference]
#> Interpretation: coefficients near zero are expected under the recoverable motifs; a negative coefficient on a variable means the states hidden by skips were higher.
attr(st, "joint")
#>        chisq           df            p 
#> 3.476809e+01 4.000000e+00 4.389214e-05 
sim0 <- simulate_ema(N = 40, n_prompts = 30, motifs = "M1", seed = 1)
silence_test(sim0$data, sim0$vars)
#> Silence test: X_{t+1} ~ X_{t-1} + R_t (within person), 637 triples, 129 with a skipped middle prompt
#>  variable coef_R    se     z     p
#>      NegA -0.296 0.127 -2.34 0.025
#>      PosA -0.054 0.101 -0.53 0.600
#>    Stress -0.147 0.102 -1.44 0.160
#>   Fatigue -0.197 0.105 -1.88 0.068
#> Joint Wald test: statistic = 8.87 on 4 df, p = 0.0847   [SE: cluster; t / F with G - 1 df reference]
#> Interpretation: coefficients near zero are expected under the recoverable motifs; a negative coefficient on a variable means the states hidden by skips were higher.
# quadratic terms in the lagged states, and a day structure
simd <- simulate_ema(N = 40, n_prompts = 30, motifs = "M2", delta = -1, days = 5, seed = 1)
silence_test(simd$data, simd$vars, day = "day", poly = 2)
#> Silence test: X_{t+1} ~ X_{t-1} + R_t (within person), 417 triples, 61 with a skipped middle prompt
#>  variable coef_R    se     z       p
#>      NegA -0.482 0.120 -4.01 0.00028
#>      PosA  0.007 0.158  0.04 0.96000
#>    Stress -0.438 0.114 -3.84 0.00045
#>   Fatigue -0.085 0.157 -0.54 0.59000
#> Joint Wald test: statistic = 26.01 on 4 df, p = 0.000435   [SE: cluster; t / F with G - 1 df reference]
#> Interpretation: coefficients near zero are expected under the recoverable motifs; a negative coefficient on a variable means the states hidden by skips were higher.