cjvanlissa / tidySEM

55 stars 7 forks source link

add support for `mediation` package #33

Open mattansb opened 3 years ago

mattansb commented 3 years ago

I think it would be very very useful if tidySEM supported mediation analysis from the mediation package.

Here is a rough draft (:

library(tidySEM)
library(mediation)

data(jobs)
b <- lm(job_seek ~ treat + econ_hard + sex + age, data=jobs)
c <- lm(depress2 ~ treat + job_seek + econ_hard + sex + age, data=jobs)

med <- mediate(b, c, sims=50, treat="treat", mediator="job_seek")

get_nodes.mediate <- function(x, ...) {
  vars_y <- insight::find_variables(x$model.y, flatten = TRUE)
  vars_m <- insight::find_variables(x$model.m, flatten = TRUE)

  var_med <- x$mediator
  var_trt <- x$treat
  var_y <- insight::find_response(x$model.y)

  out <- data.frame(
    name = union(vars_y, vars_m),
    shape = "rect"
  )
  out$label <- out$name
  out$type <- NA
  out$type <- replace(out$type, out$name == var_med, "mediator")
  out$type <- replace(out$type, out$name == var_trt, "treat")
  out$type <- replace(out$type, out$name == var_y, "outcome")
  out
}

get_edges.mediate <- function(x, label = "est", ...) {
  pars_y <- parameters::model_parameters(x$model.y, ...)
  pars_y$to <- insight::find_response(x$model.y)

  pars_m <- parameters::model_parameters(x$model.m, ...)
  pars_m$to <- insight::find_response(x$model.m)

  out <- as.data.frame(rbind(pars_y, pars_m))
  out <- out[out$Parameter!="(Intercept)",]

  colnames(out)[colnames(out)=="Parameter"] <- "from"
  colnames(out)[colnames(out)=="Coefficient"] <- "est"
  colnames(out)[colnames(out)=="SE"] <- "se"
  colnames(out)[colnames(out)=="p"] <- "pval"
  out$label <- out[[label]]
  out
}

The default layout should be something like this:

lay <- get_layout(
  # treatment and outcome
  "treat", NA, "depress2", NA, 
  # mediator
  NA, "job_seek", NA, NA, 
  # any covariates
  NA, NA, NA, "econ_hard", 
  NA, NA, NA, "sex",
  NA, NA, NA, "age",
  rows = 5)

graph_sem(edges = get_edges(med), nodes = get_nodes(med), layout = lay)

Created on 2021-07-21 by the reprex package (v2.0.0)

cjvanlissa commented 3 years ago

I support it, but it's not a priority because mediation has a low number of users (see https://ipub.com/dev-corner/apps/r-package-downloads/). If you want to develop this further, you can send a pull request and be a coauthor on the package.

Two notes on your code: 1) If you develop a method for table_results.mediate() then you don't need to develop separate get_nodes() and get_edges() methods. 2) If the layout of these results is always like that, then you could consider dynamically generating it by first placing a mediation model in rows 1:2, and then placing all covariates in the rightmost column of rows 3:numcovariates.

mattansb commented 3 years ago

(3000 weekly downloads is a little?) Hmmm is there another package you would recommend for simple mediation with covariable control?

cjvanlissa commented 3 years ago

It wasn't meant to discourage this direction, but to indicate that I highly welcome the contribution but won't develop it myself. My focus is currently on incorporating support for OpenMx, multilevel, multigroup, and mixture models. The number of users is small relative to lavaan and OpenMx.

That being said, you've got everything you need to add this with your code and my feedback (+ blessing).