Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce standardize_variables() #18

Merged
merged 21 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ S3method(mdt_within,data.frame)
S3method(mdt_within_wide,data.frame)
S3method(print,indirect_index)
S3method(print,mediation_model)
S3method(standardize_variables,data.frame)
export("%>%")
export(add_index)
export(apastylr)
Expand All @@ -30,6 +31,8 @@ export(mdt_moderated)
export(mdt_simple)
export(mdt_within)
export(mdt_within_wide)
export(standardise_variables)
export(standardize_variables)
importFrom(glue,glue)
importFrom(magrittr,"%>%")
importFrom(rlang,":=")
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# JSmediation (Development version)

* Introduce `standardize_variables` to easily center and reduce your variables.
* Introduce the `compute_indirect_effect_for()` function which computes the
indirect effect confidence interval for a specific value of the moderator in
a moderated mediation model.
Expand Down
49 changes: 24 additions & 25 deletions R/compute_indirect_effect_for.R
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
#' Compute the indirect effect index for a specific value of the moderator
#'
#' @description
#' @description
#' When computing a moderated mediation, one assesses whether an indirect
#' effect changes according a moderator value (Muller et al., 2005).
#' [`mdt_moderated`] makes it easy to assess moderated mediation, but it does
#' not allow accessing the indirect effect for a specific moderator values.
#' `compute_indirect_effect_for` fills this gap.
#'
#' @param mediation_model A moderated mediation model fitted with `mdt_moderated``.
#' @param mediation_model A moderated mediation model fitted with `mdt_moderated``.
cedricbatailler marked this conversation as resolved.
Show resolved Hide resolved
#' @param Mod The moderator value for which to compute the indirect effect. Must
#' be a numeric value, defaults to `0`.
#' @param times Number of simulations to use to compute the Monte Carlo indirect
#' effect confidence interval. Must be numeric, defaults to `5000`.
#' @param level Alpha threshold to use for the indirect effect's confidence
#' interval. Defaults to `.05`.
#'
#' @details
#'
#' @details
#' The approach used by `compute_indirect_effect_for` is similar to the
#' approach used for simple slope analyses. Specifically, it will fit a new
#' moderated mediation model, but with a data set with a different variable
#' coding. Behind the scenes, `compute_indirect_effect_for` adjusts the
#' moderator variable coding, so that the value we want to compute the
#' indirect effect for is now `0`.
#'
#'
#' Once done, a new moderated mediation model is applied using the new data
#' set. Because of the new coding, and because of how one interprets
#' coefficients in a linear regression, \eqn{a \times b}{a * b} is now the
#' indirect effect we wanted to compute (see the Models section).
#'
#' coefficients in a linear regression, \eqn{a \times b}{a * b} is now the
#' indirect effect we wanted to compute (see the Models section).
#'
#' Thanks to the returned values of \eqn{a}{a} and {b}{b} (\eqn{b_51}{b_51}
#' and \eqn{b_64}{b_64}, see the Models section), it is now easy to compute
#' \eqn{a \times b}{a * b}. `compute_indirect_effect_for` uses the same
#' approach than the [`add_index`] funcion. A Monte Carlo simulation is used
#' to compute the indirect effect index (MacKinnon et al., 2004).
#'
#'
#' @section Models: In a moderated mediation model, three models are used.
#' `compute_indirect_effect_for` uses the same model specification as
#' [`mdt_moderated`]:
Expand All @@ -57,46 +57,45 @@
#' \eqn{b_{51}}{b_51}, \eqn{b_{53}}{b_53}, \eqn{b_{64}}{b_64},
#' \eqn{b_{65}}{b_65}, \eqn{b_{41}}{b_41}, \eqn{b_{43}}{b_43},
#' \eqn{b_{61}}{b_61}, and \eqn{b_{63}}{c63} (see Muller et al., 2005).
#'
#'
#' @examples
#' # compute an indirect effect index for a specific value in a moderated
#' # compute an indirect effect index for a specific value in a moderated
#' # mediation.
#' data(ho_et_al)
#' ho_et_al$condition_c <- build_contrast(ho_et_al$condition,
#' "Low discrimination",
#' "High discrimination")
#' ho_et_al$linkedfate <- as.numeric(scale(ho_et_al$linkedfate))
#' ho_et_al$sdo <- as.numeric(scale(ho_et_al$sdo))
#' ho_et_al <- standardize_variables(ho_et_al, c(linkedfate, sdo))
#' moderated_mediation_model <- mdt_moderated(data = ho_et_al,
#' DV = hypodescent,
#' IV = condition_c,
#' M = linkedfate,
#' Mod = sdo)
#' Mod = sdo)
#' compute_indirect_effect_for(moderated_mediation_model, Mod = 0)
#'
#' @references
#' @references
#' MacKinnon, D. P., Lockwood, C. M., & Williams, J. (2004). Confidence Limits
#' for the Indirect Effect: Distribution of the Product and Resampling
#' Methods. *Multivariate Behavioral Research*, *39*(1), 99-128. doi:
#' 10.1207/s15327906mbr3901_4
#'
#'
#' Muller, D., Judd, C. M., & Yzerbyt, V. Y. (2005). When moderation
#' is mediated and mediation is moderated. *Journal of Personality and
#' Social Psychology*, *89*(6), 852-863. doi: 10.1037/0022-3514.89.6.852
#'
#' @export
compute_indirect_effect_for <- function(mediation_model,
Mod = 0,
times = 5000,
Mod = 0,
times = 5000,
level = .05) {
UseMethod("compute_indirect_effect_for")
}

#' @export
compute_indirect_effect_for.moderated_mediation <-
function(mediation_model,
Mod = 0,
times = 5000,
compute_indirect_effect_for.moderated_mediation <-
function(mediation_model,
Mod = 0,
times = 5000,
level = .05) {

# checks
Expand All @@ -112,8 +111,8 @@ compute_indirect_effect_for.moderated_mediation <-
moderator <- purrr::chuck(mediation_model, "params", "Mod")

# adjust the moderator coding so that 0 is the value we want to look at
mediation_dataset <-
mediation_dataset %>%
mediation_dataset <-
mediation_dataset %>%
dplyr::mutate(dplyr::across(.data[[moderator]], ~ .x - Mod))

# run a new moderated mediation model
Expand Down Expand Up @@ -144,7 +143,7 @@ compute_indirect_effect_for.moderated_mediation <-
)
)

indirect_sampling <- param_sampling[ , 1] * param_sampling[ , 2]
indirect_sampling <- param_sampling[ , 1] * param_sampling[ , 2]

indirect_effect(
type = glue("Conditional simple mediation index (Mod = {Mod})"),
Expand Down
11 changes: 5 additions & 6 deletions R/mdt_moderated_index.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#' Yzerbyt, 2005).
#'
#' \pkg{JSmediation} supports different types of mediated indirect effect
#' index:
#' index:
#' * **Stage 1:** computes the product between \eqn{a \times Mod}{a * Mod} and
#' \eqn{b}.
#' * **Stage 2:** computes the product between \eqn{a} and \eqn{b \times
Expand All @@ -33,8 +33,7 @@
#' ho_et_al$condition_c <- build_contrast(ho_et_al$condition,
#' "Low discrimination",
#' "High discrimination")
#' ho_et_al$linkedfate_c <- scale(ho_et_al$linkedfate, scale = FALSE)
#' ho_et_al$sdo_c <- scale(ho_et_al$sdo, scale = FALSE)
#' ho_et_al <- standardize_variables(ho_et_al, c(linkedfate, sdo), suffix ="c")
#' moderated_model <- mdt_moderated(data = ho_et_al,
#' IV = condition_c,
#' DV = hypodescent,
Expand Down Expand Up @@ -87,15 +86,15 @@ add_index.moderated_mediation <- function(mediation_model, times = 5000, level =
indirect_sampling <- ab_sampling[ , 1] * ab_sampling[ , 2]
CI <- stats::quantile(indirect_sampling, c(level / 2, 1 - level / 2))
contains_zero <- (CI[[1]] < 0 & CI[[2]] > 0)

indirect_index_infos <-
indirect_effect(type = type,
estimate = a * b,
level = level,
times = times,
sampling = indirect_sampling)
}

else if(stage %in% c("total")) {

a1 <- purrr::pluck(mediation_model, "paths", "a * Mod", "point_estimate")
Expand Down Expand Up @@ -124,7 +123,7 @@ add_index.moderated_mediation <- function(mediation_model, times = 5000, level =

indirect_sampling <- ab_sampling[ , 1] * ab_sampling[ , 2] +
ab_sampling[ , 3] * ab_sampling[ , 4]

indirect_index_infos <-
indirect_effect(
type = type,
Expand Down
67 changes: 67 additions & 0 deletions R/standarize_variables.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#' Standardize variables in a data set.
#'
#' @description `standardize_variables()` standardizes the selected columns in a
#' data.frame using \code{\link[base:scale]{scale}}. By default, this function
#' overwrites the column to be scaled. Use the `suffix` argument to avoid this
#' behavior.
#'
#' `standardize_variables()` and `standardise_variables()` are synonyms.
#'
#' @param data A data frame containing the variables to standardize.
#' @param cols <[`tidy-select`][dplyr_tidy_select]> Columns to standardize.
#' Defaults to [`dplyr::everything()`].
#' @param suffix A character suffix to be added to the scaled variables names.
#' When suffix is set to`NULL`, the `standardize_variables()` function will
#' overwrite the scaled variables. Defaults to `NULL`.
#'
#' @section `standardize_variables` and `grouped_df`:
#'
#' Note that `standardize_variables` ignores grouping. Meaning that if you
#' call this function on a grouped data frame (see [dplyr::grouped_df]), the
#' __overall__ variables' mean and standard deviation will be used for the
#' standardization.
#'
#' @return A data frame with the standardized columns.
#' @export
#'
#' @examples
#' ho_et_al %>%
#' standardize_variables(sdo)
#'
#' ho_et_al %>%
#' standardize_variables(c(sdo, linkedfate), suffix = "scaled")
standardize_variables <- function(data,
cols = dplyr::everything(),
suffix = NULL) {
UseMethod("standardize_variables")
}

#' @rdname standardize_variables
#' @export
standardise_variables <- standardize_variables

#' @export
standardize_variables.data.frame <- function(data,
cols = dplyr::everything(),
suffix = NULL) {

# store grouping variable as symbols
grouping_vars <- dplyr::groups(data)

# defines suffix
if (!is.null(suffix)) {
suffix <- glue("_{suffix}")
} else {
suffix <- ""
}

# scales variables
data %>%
dplyr::ungroup() %>%
dplyr::mutate(dplyr::across(
.cols = {{ cols }},
.fns = ~ as.numeric(scale(.x)),
.names = "{.col}{suffix}"
)) %>%
dplyr::group_by(!!!grouping_vars)
}
2 changes: 1 addition & 1 deletion _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ authors:
Dominique Muller:
href: https://www.dominique.muller.lippc2s.fr/


reference:

- title: "Fitting mediation models"
Expand Down Expand Up @@ -52,3 +51,4 @@ reference:
- contents:
- apastylr
- build_contrast
- standardize_variables
3 changes: 1 addition & 2 deletions man/add_index.moderated_mediation.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions man/compute_indirect_effect_for.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions man/standardize_variables.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading