--- title: "Serial Mediation with medfit" author: "RMediation Development Team" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Serial Mediation with medfit} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} # medfit is a Suggested (optional) dependency. Every chunk that touches it is # guarded so the vignette still builds (and CRAN checks pass) when medfit is # absent. This mirrors the runtime contract in R/ci_medfit.R, where each medfit # call site is wrapped in requireNamespace("medfit"). medfit_available <- requireNamespace("medfit", quietly = TRUE) && requireNamespace("lavaan", quietly = TRUE) knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = medfit_available ) library(RMediation) ``` ```{r medfit-missing, eval = !medfit_available, echo = FALSE, results = "asis"} cat( "> **Note:** This vignette requires the `medfit` (>= 0.2.0) and `lavaan`", "packages, which are not installed in the current environment, so the code", "below is shown but not executed. Install medfit with", "`install.packages(\"medfit\")` to run these examples.\n" ) ``` ## Why this vignette [**medfit**](https://data-wise.github.io/medfit/) is the model-fitting layer of the mediationverse: it fits mediation models and extracts the path coefficients and their covariance matrix into a tidy S7 object. RMediation then computes a confidence interval for the (possibly serial) indirect effect from that object. This division of labour means you do **not** hand-build coefficient vectors and covariance matrices yourself — `medfit::extract_mediation()` produces them, and `RMediation::ci()` consumes them directly. This vignette shows the full `fit → extract → ci()` workflow for a **serial** mediation chain (`X → M1 → M2 → Y`), for both `lavaan` and `lm`/`glm` fits. medfit is an *optional* dependency (`Suggests`): RMediation's own methods work without it, and the bridge functions error cleanly if it is missing. ## A serial chain from a lavaan fit We simulate a two-mediator chain with a known serial indirect effect `a × d1 × b = 0.5 × 0.6 × 0.7 = 0.21`, fit it with `lavaan`, and let medfit extract a `SerialMediationData` object. ```{r lavaan-fit} set.seed(42) n <- 800 X <- rnorm(n) M1 <- 0.5 * X + rnorm(n) M2 <- 0.6 * M1 + rnorm(n) Y <- 0.7 * M2 + 0.2 * X + rnorm(n) dat <- data.frame(X, M1, M2, Y) model <- "M1 ~ a*X M2 ~ d1*M1 Y ~ b*M2 + cp*X" fit <- lavaan::sem(model, data = dat) # medfit extracts the named estimates + covariance RMediation expects. mu <- medfit::extract_mediation( fit, treatment = "X", mediator = c("M1", "M2"), outcome = "Y" ) class(mu) names(mu@estimates) ``` The object carries the `a, d1, b, c_prime` name contract that RMediation's path resolver depends on. Pass it straight to `ci()`: ```{r lavaan-ci} res <- ci(mu, level = 0.95, type = "MC") res$Estimate res$CI ``` The point estimate sits near the true `0.21`, and the 95% Monte Carlo interval brackets it. ## The same chain from lm/glm fits When the mediators and outcome are fit as separate regressions, pass the first mediator model positionally, the remaining mediator models via `mediator_models`, and the outcome model via `model_y`. medfit assembles a block-structured covariance (cross-equation covariances are zero by construction, with `cov(b, c')` preserved). ```{r lm-fit} set.seed(7) n <- 800 X <- rnorm(n) M1 <- 0.5 * X + rnorm(n) M2 <- 0.6 * M1 + rnorm(n) Y <- 0.7 * M2 + 0.2 * X + rnorm(n) dat <- data.frame(X, M1, M2, Y) mu_lm <- medfit::extract_mediation( lm(M1 ~ X, dat), model_y = lm(Y ~ M2 + X, dat), treatment = "X", mediator = c("M1", "M2"), mediator_models = list(lm(M2 ~ M1, dat)) ) ci(mu_lm, level = 0.95, type = "MC")$CI ``` Both fitting routes flow through the same `ci()` call — only the upstream model object differs. ## Graceful degradation without medfit Because medfit is in `Suggests`, the bridge functions check for it at runtime. If medfit is not installed, calling them errors with an actionable message rather than failing obscurely: ```{r guard-demo, eval = FALSE} # When medfit is NOT installed, the bridge stops with a clear message: ci(mu) #> Error: Package 'medfit' is required for this method. ``` ## See also - `vignette("getting-started", package = "RMediation")` — core CI methods. - [medfit](https://data-wise.github.io/medfit/) — fitting and extraction. - `?ci` — the generic that dispatches on medfit's `MediationData` / `SerialMediationData` objects.