drm_pair() records a bivariate node: two responses to be fitted jointly
with a residual correlation rho12 (the within-observation coupling that
remains after each response's mean and scale), optionally modelled as a
function of predictors (rho12 ~ x, a directed path into the correlation
component), and — when the two response formulas share a grouping level — a
higher-level random-effect correlation (corpair). It is the bivariate
counterpart of drm_node().
Usage
drm_pair(
formula1,
formula2,
rho12 = NULL,
family = stats::gaussian(),
family2 = family,
level = NULL,
names = NULL
)Arguments
- formula1, formula2
Two two-sided response formulas (e.g.
activity ~ x + (1 | id)andboldness ~ x + (1 | id)). Random-effect bar groups shared between the two declare the higher-levelcorpairedge.- rho12
Optional one-sided formula (e.g.
~ x) giving predictors of the residual correlation on its link (tanh) scale — a directed path into therho12component.NULL(default) declares a constant residual correlation.- family, family2
drmTMB/statsfamilies for the two responses.family2defaults tofamily(a homogeneous bivariate node).- level
Higher-level (
corpair) grouping.NULL(default) auto-detects grouping factors common to both formulas; a string forces a specific level;NAsuppresses thecorpairedge (residualrho12only).- names
Optional length-2 character vector of node names, defaulting to the two response labels.
Details
This is the declaration grammar, not the fit. drmSEM is piecewise and the
dev lane has no engine, so drm_pair() does not estimate rho12: it validates
the declaration and bridges it onto the shipped covariance-edge grammar
(covary() / covariances()), so the residual (rho12) and higher-level
(corpair) arcs are reported separately from paths() and respected by
basis_set() / dsep(). Estimating rho12 inside one joint drmTMB model —
and reading it back through rho12() / corpairs() — is the 0.4 engine
deliverable (see docs/design/07-bivariate-covariance-edges.md). The declared
estimates are NA until a live bivariate fit is supplied; drm_pair() never
fabricates a correlation.
References
Shipley B (2016). Cause and Correlation in Biology: A User's Guide to Path Analysis, Structural Equations and Causal Inference with R, 2nd edition. Cambridge University Press, Cambridge.
Bollen KA (1989). Structural Equations with Latent Variables. Wiley, New York.
Brooks ME, Kristensen K, van Benthem KJ, Magnusson A, Berg CW, Nielsen A, Skaug HJ, Maechler M, Bolker BM (2017). “glmmTMB Balances Speed and Flexibility Among Packages for Zero-Inflated Generalized Linear Mixed Models.” The R Journal, 9(2), 378–400. doi:10.32614/RJ-2017-066 .
Examples
# A bivariate node: two responses sharing an `id` grouping, with the residual
# correlation itself modelled as a function of `x`.
pair <- drm_pair(
activity ~ x + (1 | id),
boldness ~ x + (1 | id),
rho12 = ~ x
)
pair
#>
#> ── <drm_pair> bivariate node "activity" & "boldness"
#> activity [gaussian]: `activity ~ x + (1 | id)`
#> boldness [gaussian]: `boldness ~ x + (1 | id)`
#> residual correlation: rho12 ~ x [directed path into rho12]
#> higher-level correlation: corpair at 1 level ("id")
#> estimates: NA (declared; joint bivariate fit is the 0.4 engine step)
rho12(pair) # declared residual edge (estimate NA -> needs a joint fit)
#> <residual correlation (rho12): 1 edge>
#> y1 y2 predictors constant estimate
#> activity boldness x FALSE NA
#> estimate NA: rho12/corpair are declared; a joint bivariate drmTMB fit is needed
#> to read fitted values back (OQ-14, 0.4 engine).
corpairs(pair) # declared higher-level edge at the shared `id` level
#> <higher-level correlation (corpair): 1 edge>
#> level y1 y2 estimate
#> id activity boldness NA
#> estimate NA: rho12/corpair are declared; a joint bivariate drmTMB fit is needed
#> to read fitted values back (OQ-14, 0.4 engine).