---
title: "User-defined mediation models with GenerateModelCustom"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{User-defined mediation models with GenerateModelCustom}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---



## 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:


``` r
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.


``` r
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.


``` r
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:


``` r
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:


``` r
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

```r
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.


``` r
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.


``` r
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](StandardizedModeratedMediation.html)
for raw-unit probing, categorical coding and uncertainty in the scale factors.
