Skip to contents

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) and boldness ~ x + (1 | id)). Random-effect bar groups shared between the two declare the higher-level corpair edge.

rho12

Optional one-sided formula (e.g. ~ x) giving predictors of the residual correlation on its link (tanh) scale — a directed path into the rho12 component. NULL (default) declares a constant residual correlation.

family, family2

drmTMB/stats families for the two responses. family2 defaults to family (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; NA suppresses the corpair edge (residual rho12 only).

names

Optional length-2 character vector of node names, defaulting to the two response labels.

Value

A drm_pair declaration object.

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).