---
title: "Set Moderator Levels"
author: "Shu Fai Cheung & Sing-Hang Cheung"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    number_sections: true
vignette: >
  %\VignetteIndexEntry{Set Moderator Levels}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

# Introduction

This article is a brief illustration of how
to use `mod_levels()`,
`mod_levels_list()`, and `merge_mod_levels()`
from the package
[manymome](https://sfcheung.github.io/manymome/)
([Cheung & Cheung, 2024](https://doi.org/10.3758/s13428-023-02224-z))
to generate a table of moderator levels for use
by `cond_indirect_effects()`. No need to use these
functions if the default levels generated by
`cond_indirect_effects()` is appropriated,
 as illustrated in `vignette("manymome")`.

Use these functions only when users want to use levels
of the moderators other than those default levels.

# Numeric Moderators

We first use the sample data set `data_med_mod_ab`:

```{r}
library(manymome)
dat <- data_med_mod_ab
print(head(dat), digits = 3)
```

Suppose this is the model being fitted:

```{r}
library(lavaan)
dat$w1x <- dat$w1 * dat$x
dat$w2m <- dat$w2 * dat$m
mod <-
"
m ~ x + w1 + w1x
y ~ m + w2 + w2m
m ~~ w2 + w2m
w2  ~~ w2m + x + w1 + w1x
w2m ~~ x + w1 + w1x
x   ~~ w1 + w1x
w1  ~~ w1x
"
fit <- sem(model = mod, data = dat)
```

## SD and Mean

It has two numeric moderators, `w1` and `w2`. To
generate these three levels for `w1`, one standard
deviation (SD) below mean, mean, and one SD above
mean, just call `mod_levels()`:

```{r}
w1levels <- mod_levels(w = "w1", fit = fit)
w1levels
```

This is not necessary in calling `cond_indirect_effects()`
because it will automatically generate these default
levels.

Suppose we want to use only two levels, one SD below and
one SD above mean, we can set the argument `sd_from_mean`
to a vector of distances from means, which are `-1` and
`1` in this example:

```{r}
w1levels <- mod_levels(w = "w1", fit = fit,
                       sd_from_mean = c(-1, 1))
w1levels
```

## Percentiles

To generate the levels based on percentiles, set the
argument `w_method` to `"percentile"`:

```{r}
w1levels <- mod_levels(w = "w1", fit = fit,
                       w_method = "percentile")
w1levels
```

The default percentiles are 16th, 50th, and 84th, corresponding
to one SD below mean, mean, and one SD above mean in a
normal distribution.

Suppose we want to change the percentiles to be used,
for example, 25th and 75th, set the argument `percentiles`
as shown below:

```{r}
w1levels <- mod_levels(w = "w1", fit = fit,
                       w_method = "percentile",
                       percentiles = c(.25, .75))
w1levels
```

## Specific Values

If there are values that are meaningful for a moderator,
they can be used by setting `values` to a vector of values:

```{r}
w1levels <- mod_levels(w = "w1", fit = fit,
                       values = c(2, 4, 8))
w1levels
```

The output of `mod_levels` can be used when calling
`cond_indirect_effects()`:

```{r}
out <- cond_indirect_effects(wlevels = w1levels,
                             x = "x", y = "m",
                             fit = fit)
out
```

`cond_indirect_effects()` will determine the moderators
automatically from the object assigned to `wlevels`.

## Merging the Levels of Two Or More Moderators

In the previous example, there are two moderators.
We can
call `mod_levels()` once for each of them, or call
`mod_levels_list()`:

```{r}
wlevels_list <- mod_levels_list("w1", "w2", fit = fit)
wlevels_list
```

The output is a list of the output of `mod_levels()`.
With two or more moderators, the default levels are
two: one SD below mean and one SD above mean.

The function `mod_levels_list()`
can merge the output into one table by setting `merge` to `TRUE`:

```{r}
wlevels_list <- mod_levels_list("w1", "w2", fit = fit,
                                merge = TRUE)
wlevels_list
```

Calling `mod_levels_list()` is useful when the same settings will
be used for all moderators. Most arguments of `mod_levels()`
can be used in `mod_levels_list()`. For example, if we want to use
25th and 75th percentiles for both `w1` and `w2`, use `w_method`
and `percentiles` as before:

```{r}
wlevels_list <- mod_levels_list("w1", "w2", fit = fit,
                                w_method = "percentile",
                                percentiles = c(.25, .75),
                                merge = TRUE)
wlevels_list
```

## Different Settings For Moderators

If we need to use different settings for the two moderators,
then we need to call `mod_levels()` once for each of them,
and merge the results by `merge_mod_levels()`:

```{r}
w1levels <- mod_levels(w = "w1", fit = fit)
w1levels
w2levels <- mod_levels(w = "w2", fit = fit, values = c(2, 5))
w2levels
wlevels_all <- merge_mod_levels(w1levels, w2levels)
wlevels_all
```

# Categorical Moderators

We use the dataset `data_med_mod_serial_cat` for illustration:

```{r}
dat <- data_med_mod_serial_cat
print(head(dat), digits = 3)
```

It has two categorical moderators, `w1` with three categories
and `w2` with two categories. We use only `w1` here
for illustration.

## Create Dummy Variables and Fit the Model

To fit a model using path analysis, two dummy variables need
to be created for `w1`. This can be done by `factor2var()`
or similar functions from other packages.

```{r}
w1dummies <- factor2var(dat$w1, prefix = "w1")
head(w1dummies)
# Add them to the dataset
dat[, c("w1group2", "w1group3")] <- w1dummies
print(head(dat), digits = 3)
```

This is the model:

```{r}
dat$w1group2x <- dat$w1group2 * dat$x
dat$w1group3x <- dat$w1group3 * dat$x
mod <-
"
m1 ~ x + w1group2 + w1group3 + w1group2x + w1group3x
y ~ m1 + x
"
fit <- sem(model = mod, data = dat)
```

## Default Levels

The levels of a categorical moderator are just the
categories (unique combinations of the coding). This
can be generated by `mod_levels()`.
`w` should be a vector of the dummy variables:

```{r}
w1levels <- mod_levels(w = c("w1group2", "w1group3"), fit = fit)
w1levels
```

The names of `group2` and `group3` are `2` and `3` because they
are inferred from the names of the dummy variables. The common part,
`"w1group"`, is removed.

To tell `mod_levels` which part to be removed, set `prefix` to the
part to be removed:

```{r}
w1levels <- mod_levels(w = c("w1group2", "w1group3"), fit = fit,
                       prefix = "w1")
w1levels
```

By default, the group with 0s on all dummy variables is
labelled `Reference` because its name cannot be determined
from the names of the dummy variables.
The label can be changed by setting `reference_group_label`:

```{r}
w1levels <- mod_levels(w = c("w1group2", "w1group3"), fit = fit,
                       prefix = "w1",
                       reference_group_label = "group1")
w1levels
```

The output can then be used in `cond_indirect_effects()`:

```{r}
out <- cond_indirect_effects(wlevels = w1levels,
                             x = "x", y = "y", m = "m1",
                             fit = fit)
out
```

## User-Supplied Levels

To have full control on the labels and coding, use `values`
and supply a *named* *list* of numeric vectors:
the *name* is the group label and the *vector* is the coding:

```{r}
w1levels <- mod_levels(w = c("w1group2", "w1group3"), fit = fit,
                       values = list(group1 = c(0, 0),
                                     group2 = c(1, 0),
                                     group3 = c(0, 1)))
w1levels
```

# Mixing Numeric and Categorical Moderators

Numeric and categorical moderators can be mixed but they
need to be generated separately and then merged by
`merge_mod_levels()`.

Using the example in the previous section, pretending that
`x` is a numeric moderator:

```{r}
xlevels <- mod_levels(w = "x", fit = fit,
                      sd_from_mean = c(-1, 1))
xlevels
w1levels <- mod_levels(w = c("w1group2", "w1group3"), fit = fit,
                       prefix = "w1",
                       reference_group_label = "group1")
w1levels
wlevels_all <- merge_mod_levels(xlevels, w1levels)
wlevels_all
```

# Determining The Type of a Moderator

The function `mod_levels()` and `mod_levels_list()`
usually can determine the type correctly. However,
if the detected type is wrong or users want to
specify explicitly the type, set the argument `w_type`
to either `"numeric"` or `"categorical"`.

# Further Information

For further information on `mod_levels()`,
`mod_levels_list()`, and `merge_mod_levels()`,
please refer to their help pages.

# Reference

Cheung, S. F., & Cheung, S.-H. (2024).
*manymome*: An R package for computing
the indirect effects, conditional
effects, and conditional indirect
effects, standardized or unstandardized,
and their bootstrap confidence intervals,
in many (though not all) models.
*Behavior Research Methods, 56*(5),
4862--4882.
https://doi.org/10.3758/s13428-023-02224-z