User-defined mediation models with GenerateModelCustom

Introduction

GenerateModelCustom() generates lavaan syntax for a user-defined two-condition within-subject mediation model. It is useful when the intended mediator structure cannot be represented by one of the predefined parallel, chained, chained–parallel, or parallel–chained models in wsMed.

Users specify directed paths among mediators and from mediators to the outcome. For example:

custom_paths <- c(
  "M1 -> M3",
  "M3 -> Y",
  "M2 -> Y"
)

Here, M1, M2, and M3 denote the mediators, and Y denotes the outcome. The user does not specify paths beginning with X. The function automatically adds an \(a_i\) path from the within-subject condition to every mediator and the direct effect \(cp\) from the condition to the outcome.

Mediator numbering

Mediator labels are assigned according to the order of the variables supplied to M_C1 and M_C2. For example:

Construct Condition 1 Condition 2 Model label
A A1 A2 M1
B B1 B2 M2
C C1 C2 M3
D D1 D2 Y

Therefore, "M1 -> M3" represents a path from construct A to construct C. Mediator numbering identifies variables; it does not determine path direction.

Preparing example data

The following reproducible example creates three mediator pairs and one outcome pair. It does not depend on an external data file.

set.seed(123)
n <- 200

example_custom <- data.frame(
  A1 = rnorm(n),
  A2 = rnorm(n, mean = 0.30),
  B1 = rnorm(n),
  B2 = rnorm(n, mean = 0.20),
  C1 = rnorm(n),
  C2 = rnorm(n, mean = 0.25),
  D1 = rnorm(n),
  D2 = rnorm(n, mean = 0.35)
)

PrepareData() converts the raw condition-specific variables into mediator difference and centered level components and an outcome difference score.

prepared_data <- PrepareData(
  data = example_custom,
  M_C1 = c("A1", "B1", "C1"),
  M_C2 = c("A2", "B2", "C2"),
  Y_C1 = "D1",
  Y_C2 = "D2"
)

names(prepared_data)
#> [1] "Ydiff"  "M1diff" "M2diff" "M3diff" "M1avg"  "M2avg"  "M3avg"

For mediator \(M_i\), the two components are

\[ M_{i,\mathrm{diff}} = M_{i2} - M_{i1} \]

and

\[ M_{i,\mathrm{avg}} = \frac{M_{i1} + M_{i2}}{2}, \]

where the average component is centered by PrepareData().

Specifying a custom model

Each element of paths must describe either a mediator-to-mediator path or a mediator-to-outcome path:

custom_paths <- c(
  "M1 -> M3",
  "M3 -> Y",
  "M2 -> Y"
)

Spaces around -> are optional. For example, "M1 -> M3" and "M1->M3" are equivalent.

The corresponding model syntax is generated as follows:

custom_model <- GenerateModelCustom(
  prepared_data = prepared_data,
  paths = custom_paths
)

cat(custom_model)
#> Ydiff ~ cp*1 + b2*M2diff + d2*M2avg + b3*M3diff + d3*M3avg
#> M1diff ~ a1*1
#> M2diff ~ a2*1
#> M3diff ~ a3*1 + b_1_3*M1diff + d_1_3*M1avg
#> indirect_1_3 := a1 * b_1_3 * b3
#> indirect_2 := a2 * b2
#> indirect_3 := a3 * b3
#> total_indirect := indirect_1_3 + indirect_2 + indirect_3
#> total_effect := cp + total_indirect

For every specified structural edge, the generated regression includes both the difference and level components of the predictor mediator. Thus, "M1 -> M3" contributes

b_1_3*M1diff + d_1_3*M1avg

to the regression equation for M3diff.

Only specified structural paths are added. Because "M1 -> Y" is absent from custom_paths, M1diff and M1avg do not appear directly in the regression equation for Ydiff.

Indirect effects

GenerateModelCustom() identifies every directed path from a mediator to Y. The model above contains three indirect effects: \[ \mathtt{indirect\_1\_3} = \mathtt{a1}\, \mathtt{b\_1\_3}\, \mathtt{b3}, \]

\[ \mathtt{indirect\_2} = \mathtt{a2}\, \mathtt{b2}, \]

\[ \mathtt{indirect\_3} = \mathtt{a3}\, \mathtt{b3}. \]

The last effect exists because the path from the condition to every mediator, including \(M_3\), is added automatically. All identified indirect effects are summed to form total_indirect, and the total effect is defined as cp + total_indirect.

Parameter labels

The generated model uses the following labels:

Path Difference component Level component
\(X \rightarrow M_i\) ai
\(M_i \rightarrow Y\) bi di
\(M_j \rightarrow M_i\) b_j_i d_j_i
\(X \rightarrow Y\) cp

For example, the path \(M_1 \rightarrow M_3\) uses b_1_3 and d_1_3, whereas \(M_3 \rightarrow Y\) uses b3 and d3.

Fitting the complete model with wsMed

For an applied analysis, users can pass the same path specification directly to wsMed() by setting form = "UD".

The following chunk is not evaluated while the vignette is knitted because Monte Carlo confidence intervals can take some time. Remove eval=FALSE to run it.

result_custom <- wsMed(
  data = example_custom,
  M_C1 = c("A1", "B1", "C1"),
  M_C2 = c("A2", "B2", "C2"),
  Y_C1 = "D1",
  Y_C2 = "D2",
  form = "UD",
  paths = custom_paths,
  Na = "DE",
  ci_method = "mc",
  R = 5000,
  standardized = TRUE,
  seed = 123
)

print(result_custom)

Input requirements

A valid custom path specification must meet the following requirements:

  1. Each path must use a form such as "M1 -> M2" or "M2 -> Y".
  2. Every referenced mediator must be present in prepared_data.
  3. Duplicate paths and self-loops such as "M1 -> M1" are not allowed.
  4. The mediator structure must be acyclic.
  5. At least one mediator must have a path ending in Y.

Paths beginning with X, such as "X -> M1" or "X -> Y", should not be included because these paths are added automatically. Paths beginning with Y are not permitted because Y is the final outcome.

Summary

To fit a user-defined model:

  1. Supply matched mediator variables through M_C1 and M_C2.
  2. Define the structural edges using mediator labels and Y.
  3. Use GenerateModelCustom() to inspect the generated syntax or call wsMed(form = "UD", paths = ...) for the complete analysis.

This workflow retains the existing difference-and-level parameterization in wsMed while allowing users to specify mediation structures beyond the four predefined model forms.

Standardized moderated custom models

The same endpoint scaling applies to a sparse user-defined model. Only paths present in paths can be requested in MP. For the model above, b_1_3 and b3 exist, whereas b1 does not.

set.seed(321)
example_custom$W <- rnorm(nrow(example_custom))
custom_moderated <- wsMed(
  data = example_custom,
  M_C1 = c("A1", "B1", "C1"), M_C2 = c("A2", "B2", "C2"),
  Y_C1 = "D1", Y_C2 = "D2", form = "UD",
  paths = c("M1 -> M3", "M3 -> Y", "M2 -> Y"),
  W = "W", W_type = "continuous", MP = c("b_1_3", "b3"),
  Na = "DE", ci_method = "mc", R = 2000, seed = 321,
  standardized = TRUE, verbose = FALSE
)
head(custom_moderated$moderation_std$beta_coef)
#>                  Path Mediators Level W_value    Estimate         SE  2.5.%CI.Lo 97.5.%CI.Up Sig
#> 1 indirect_effect_1_3       1 3 -1 SD  -0.930 -0.00171108 0.00930085 -0.02141640  0.01760392    
#> 2 indirect_effect_1_3       1 3  0 SD   0.004 -0.00246412 0.00323804 -0.01037716  0.00255513    
#> 3 indirect_effect_1_3       1 3 +1 SD   0.937 -0.00091161 0.00258922 -0.00743724  0.00315255    
#> 4   indirect_effect_2         2 -1 SD  -0.930 -0.00419233 0.01070311 -0.03017033  0.01513924    
#> 5   indirect_effect_2         2  0 SD   0.004 -0.00424159 0.00918899 -0.02724825  0.01246020    
#> 6   indirect_effect_2         2 +1 SD   0.937 -0.00429085 0.01089494 -0.03130748  0.01468530
custom_moderated$moderation_std$conditional_overall
#>           Effect Level W_value    Estimate         SE  2.5.%CI.Lo 97.5.%CI.Up Sig
#> 1 total_indirect -1 SD  -0.930 -0.00084796 0.02190236 -0.04624817  0.04603392    
#> 3 total_indirect  0 SD   0.004  0.00807649 0.01717070 -0.02427926  0.04448637    
#> 5 total_indirect +1 SD   0.937  0.01598798 0.02552867 -0.02705751  0.07551097    
#> 2   total_effect -1 SD  -0.930  0.22931289 0.09962514  0.03219760  0.42551819   *
#> 4   total_effect  0 SD   0.004  0.32274183 0.07074161  0.18614681  0.46708409   *
#> 6   total_effect +1 SD   0.937  0.41515782 0.10004355  0.21574178  0.61416485   *

The total indirect effect includes every complete path in this model, including paths without a requested interaction. Moderator main effects already fitted in the mediator and outcome regressions enter conditional intercepts even though a and cp were not requested in MP. See Standardized moderated mediation for raw-unit probing, categorical coding and uncertainty in the scale factors.