jslefche / piecewiseSEM

Piecewise Structural Equation Modeling in R
157 stars 49 forks source link

multigroup fails for lme4 #209

Open jslefche opened 4 years ago

jslefche commented 4 years ago
library(piecewiseSEM)
library(lme4)

# Generate data
data <- data.frame(
  x1 = rnorm(100),
  y1 = rnorm(100),
  y2 = rnorm(100),
  groups = LETTERS[1:2],
  random = rep(letters[1:4], each = 25)
)

model <- psem(
  lmer(y1 ~ x1 + (1 | random), data),
  lmer(y2 ~ y1 + (1 | random), data),
  data = data)

multigroup(model, group = "groups")
elisalonso commented 4 years ago

Hi Jon,

The problem arises from a section in the multigroup() function where the new models with the interaction with 'group' is created.

Line 39 of multigroup.R:

rhs2 <- paste(paste(all.vars_trans(i)[-1], "*", group), collapse = " + ")

creates the new models by pasting the fixed terms and adding an interaction with 'group'. The problem is that in lme4 the random factors should be included as part of the formula too.

I managed to fix the problem by changing that line of code to:

rhs2 <- ifelse(class(i) == "lmerMod", paste(paste(paste(all.vars_trans(i)[-1], "*", group), collapse = " + "), "+ (", findbars(formula(i)),")"), paste(paste(all.vars_trans(i)[-1], "*", group), collapse = " + "))

This fixed the problem for me.

However, in this case, the data always has to be added as part of the psem() model, otherwise the function cannot find the 'group' variable. I believe this is due to lme4 models not storing the data as part of their output.

elisalonso commented 4 years ago

I realise now that the solution above only works if the model is of class "lmerMod", which is only applicable to lme4::lmer() models. For the code to also work with other model types from the lme4 package, the code should read:

rhs2 <- ifelse(grepl("merMod", class(i)) == T, paste(paste(paste(all.vars_trans(i)[-1], "*", group), collapse = " + "), "+ (", findbars(formula(i)),")"), paste(paste(all.vars_trans(i)[-1], "*", group), collapse = " + "))

misatoda commented 3 years ago

Hi,

I tried multigroup function with lme4 for "lmerMod" class object after changed the line 39 rhs2 <- paste(paste(all.vars_trans(i)[-1], "", group), collapse = " + ") to rhs2 <- ifelse(class(i) == "lmerMod", paste(paste(paste(all.vars_trans(i)[-1], "", group), collapse = " + "), "+ (", findbars(formula(i)),")"), paste(paste(all.vars_trans(i)[-1], "*", group), collapse = " + "))

according to the previous post.

Then, I got the new error message saying:

Error in removeData(modelList, formulas = 1) : could not find function "removeData"

I ran the following function to make sure "removeData" is in the R.

removeData <- function(modelList, formulas = 0) {

remove <- c("character", "matrix", "data.frame", "SpatialPointsDataFrame", "comparative.data")

if(formulas == 1) remove <- c(remove, "formula", "formula.cerror")

if(formulas == 2) remove <- c(remove, "formula")

if(formulas == 3) remove <- c(remove, "formula.cerror")

modelList[!sapply(modelList, function(x) any(class(x) %in% remove))]

}

After that, when I ran multigroup, I got another error message below.

Error in all.vars_trans(i) : could not find function "all.vars_trans"

Then I ran the following function

all.vars_trans <- function(formula.) {

if(!all(class(formula.) %in% c("formula", "formula.cerror"))) formula. <- formula(formula.)

if(class(formula.) == "formula") {

if(formula.[[3]] == 1) deparse(formula.[[2]]) else {

  if(any(grepl("\\|", formula.))) formula. <- lme4::nobars(formula.)

  c(rownames(attr(terms(formula.), "factors"))[1], labels(terms(formula.)))

}

} else unlist(strsplit(formula., " ~~ "))

}

Then I got the error message below.

Error in [.data.frame(data, , group) : undefined columns selected

Sorry, I am not so good at R yet and have no clue what is the problem.

I am using R version 4.1.2, piesewiseSEM 2.1.2 (I am a bit confused about the piesewiseSEM version because I installed the latest version, 2.1.2, and it says 2.1.2 in the package description in R studio but in the R console, when I load the package, it says 2.1.0. But even if my piesewiseSEM is 2.1.0, it should have removeData function).

Thank you.

MBGarfinkel commented 1 year ago

I have also been trying to make the proposed change to the code so that I can run multigroup() with a lme4 model, but have run into the same problems as the previous commenter. Are there any plans to fix this in the package or can you suggest a way for a relative beginner to make the change?

JCZ9527 commented 7 months ago

I have been tried to run multigroup() with a lm model, but have run into the same problems as the previous commenter. 1.Error in [.data.frame(data, , group) : undefined columns selected 2.Error in removeData(modelList, formulas = 1) :could not find function "removeData"