Skip to first unread message

Sep 29, 2022, 5:54:21 PM9/29/22

to lavaan

Sorry for my maybe lame question, I googled a lot but didn't find a solution:

I would like to do a regression with a interaction term in lavaan, but I can't find out, how to do that. In lm I simply would run a model as "posttest ~ pretest + predictor*moderator" but in lavaan I understand the * works differently. In several post I read, I could just use the semicolon instead, but then I get a "lavaan ERROR: missing observed variables in dataset: predictor:mediator".

So please, where can I find good information on how to do this properly in lavaan? This is just a simplified example, in the end I would like to run a 2-level regression with a categorical moderator (group) on level 1, but if I can't even do the very simple model...

Thanks a lot in advance for your support and for all your great work out there! ;)

Cheers, Martin

Sep 29, 2022, 8:17:51 PM9/29/22

to lav...@googlegroups.com

If your model is just a regression, you create the moderator outside the model statement.

Something like:

my_data <-

my_data %>%

dplyr::mutate(m_x_p = moderator * predictor)

Then your lavaan model looks like:

posttest ~ pretest + predictor + moderator + m_x_p

If your moderator (or predictor) is categorical there is also the option of multiple groups, which allows you to relax some assumptions.

Jeremy

--

You received this message because you are subscribed to the Google Groups "lavaan" group.

To unsubscribe from this group and stop receiving emails from it, send an email to lavaan+un...@googlegroups.com.

To view this discussion on the web visit https://groups.google.com/d/msgid/lavaan/d928e968-e3ae-4bee-a239-de7fffebf71an%40googlegroups.com.

Sep 30, 2022, 4:47:52 AM9/30/22

to lavaan

Thanks a lot, Jeremy, for the quick reply. That's kind of the "SPSS"-method, not very elegant, but should work, indeed. As for the multigroup: I actually already tried this, but wasn't sure about the interpretation of the result. In one group the investigated predictor was signicifant, in the other group it wasn't - is this enough to say, that the group affilation is a moderator of the prediction?

Thanks, Martin

Sep 30, 2022, 5:30:53 AM9/30/22

to lav...@googlegroups.com

Hi Martin,

no, this is not sufficient. There are several ways to test the moderator effect. Two examples:

library(lavaan)

# Method 1

HS.model <- "

f1 =~ x1 + x2 + x3

f2 =~ x4 + x5 + x6

f2 ~ c(bg1, bg2) * f1

mod := bg2 - bg1

"

fit <- sem(HS.model, data = HolzingerSwineford1939, group = "school")

pe <- parameterEstimates(fit)

pe[pe$op == "~",]

pe[pe$op == ":=",]

# Method 2

HS.model.uncon <- "

f1 =~ x1 + x2 + x3

f2 =~ x4 + x5 + x6

f2 ~ c(bg1, bg2) * f1

"

HS.model.con <- "

f1 =~ x1 + x2 + x3

f2 =~ x4 + x5 + x6

f2 ~ c(bg1, bg2) * f1

bg1 == bg2

"

fit.uncon <- sem(HS.model.uncon, data = HolzingerSwineford1939, group = "school")

fit.con <- sem(HS.model.con, data = HolzingerSwineford1939, group = "school")

lavTestLRT(fit.uncon, fit.con)

In the first case, the difference of the effects is tested. In the second case, the model is compared to a nested model where it is assumed that the effects do not differ. If you prefer resampling techniques, you can use bootstrapping for method 1. For method 2, permutation tests should be applicable (in the latter case I am not 100% sure).

Christian

To view this discussion on the web visit
https://groups.google.com/d/msgid/lavaan/68f908e0-52d5-46c7-b1a8-a0d5adb61d58n%40googlegroups.com.

Oct 1, 2022, 4:49:26 PM10/1/22

to lavaan

Dear Christian,

Thanks a lot for this detailed answer. I tried to implement it with my 2-level model, but I get an error message "Fehler in ov.names.l[[g]] : Indizierung außerhalb der Grenzen" (I assume you speak German).

This is my code:

dta.ATI <- fscores.I0_I1 |>

dplyr::select("Pre_z", "Post","Lehrperson","SR3.theta","math.fscores","Gruppe") |>

na.omit()

dta.ATI$Gruppe <- droplevels(dta.ATI$Gruppe)

dta.ATI$Gruppe <- recode(dta.ATI$Gruppe,"'I0'=0; 'I1'=1") #Dummykodierung mit Zahlen

dta.ATI <-scale_ignore(dta.ATI,ignore=c("Lehrperson","Gruppe")) #Alle Variablen skalieren und zentrieren, damit lavaan sauber durchläuft

lavmodeldef <- "

level: 1

Post ~ Pre_z + c(bg1,bg2)*SR3.theta

level: 2

Post ~ Pre_z

dplyr::select("Pre_z", "Post","Lehrperson","SR3.theta","math.fscores","Gruppe") |>

na.omit()

dta.ATI$Gruppe <- droplevels(dta.ATI$Gruppe)

dta.ATI$Gruppe <- recode(dta.ATI$Gruppe,"'I0'=0; 'I1'=1") #Dummykodierung mit Zahlen

dta.ATI <-scale_ignore(dta.ATI,ignore=c("Lehrperson","Gruppe")) #Alle Variablen skalieren und zentrieren, damit lavaan sauber durchläuft

lavmodeldef <- "

level: 1

Post ~ Pre_z + c(bg1,bg2)*SR3.theta

level: 2

Post ~ Pre_z

mod := bg2 - bg1

"

#this is your model as proposed:

# f1 =~ x1 + x2 + x3

# f2 =~ x4 + x5 + x6

# f2 ~ c(bg1, bg2) * f1

# mod := bg2 - bg1

fit <- sem(lavmodeldef, data = dta.ATI, cluster = "Lehrperson", estimator="MLR",group="Gruppe")

# f1 =~ x1 + x2 + x3

# f2 =~ x4 + x5 + x6

# f2 ~ c(bg1, bg2) * f1

# mod := bg2 - bg1

fit <- sem(lavmodeldef, data = dta.ATI, cluster = "Lehrperson", estimator="MLR",group="Gruppe")

pe <- parameterEstimates(fit)

pe[pe$op == "~",]

pe[pe$op == ":=",]

----END OF CODE----

Here is the structure of dta.ATI:

> str(dta.ATI)

'data.frame': 170 obs. of 6 variables:

$ Pre_z : num 1.204 1.05 0.876 0.364 -0.834 ...

$ Post : num -0.0232 0.4186 0.8905 0.6055 -1.2467 ...

$ Lehrperson : Factor w/ 17 levels "1980","2690",..: 15 15 15 15 15 15 15 15 15 15 ...

$ SR3.theta : num 2.027 0.364 2.027 2.027 -0.868 ...

$ math.fscores: num 0.919 0.593 0.593 0.593 -2.017 ...

$ Gruppe : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...

'data.frame': 170 obs. of 6 variables:

$ Pre_z : num 1.204 1.05 0.876 0.364 -0.834 ...

$ Post : num -0.0232 0.4186 0.8905 0.6055 -1.2467 ...

$ Lehrperson : Factor w/ 17 levels "1980","2690",..: 15 15 15 15 15 15 15 15 15 15 ...

$ SR3.theta : num 2.027 0.364 2.027 2.027 -0.868 ...

$ math.fscores: num 0.919 0.593 0.593 0.593 -2.017 ...

$ Gruppe : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...

What am I'm doing wrong? Before I had to add "group: 1" and "group :2" lines to the model avoid this error, but now this also leads to an error.

Thanks a lot in advance, Martin

Oct 1, 2022, 5:39:15 PM10/1/22

to lavaan

I think I could solve the problem myself. This code seems to work (I'm glad if somebody can verify it):

dta.ATI <- fscores.I0_I1 |>

dplyr::select("Pre_z", "Post","Lehrperson","SR3.theta","math.fscores","Gruppe") |>

na.omit()

dta.ATI$Gruppe <- droplevels(dta.ATI$Gruppe)

dta.ATI$Gruppe <- recode(dta.ATI$Gruppe,"'I0'=0; 'I1'=1") #Dummykodierung mit Zahlen

dta.ATI <-scale_ignore(dta.ATI,ignore=c("Lehrperson","Gruppe")) #Alle Variablen skalieren und zentrieren, damit lavaan sauber durchläuft

dplyr::select("Pre_z", "Post","Lehrperson","SR3.theta","math.fscores","Gruppe") |>

na.omit()

dta.ATI$Gruppe <- droplevels(dta.ATI$Gruppe)

dta.ATI$Gruppe <- recode(dta.ATI$Gruppe,"'I0'=0; 'I1'=1") #Dummykodierung mit Zahlen

dta.ATI <-scale_ignore(dta.ATI,ignore=c("Lehrperson","Gruppe")) #Alle Variablen skalieren und zentrieren, damit lavaan sauber durchläuft

#Version 1, difference of bg2 and bg1

lavmodeldef <- "

Group: 1

level: 1

Post ~ Pre_z + bg1*SR3.theta +math.fscores

level: 2

Post ~ Pre_z + math.fscores

Group: 2

level: 1

Post ~ Pre_z + bg2*SR3.theta + math.fscores

level: 2

Post ~ Pre_z + math.fscores

mod := bg2 - bg1

"

fit <- sem(lavmodeldef, data = dta.ATI, cluster = "Lehrperson", estimator="MLR",group="Gruppe")

pe <- parameterEstimates(fit)

pe[pe$op == "~",]

pe[pe$op == ":=",]

pe <- parameterEstimates(fit)

pe[pe$op == "~",]

pe[pe$op == ":=",]

#Version 2, nested models

lavmodeldef.uncon <- "

Group: 1

level: 1

Post ~ Pre_z + bg1*SR3.theta +math.fscores

level: 2

Post ~ Pre_z + math.fscores

Group: 2

level: 1

Post ~ Pre_z + bg2*SR3.theta + math.fscores

level: 2

Post ~ Pre_z + math.fscores

"

lavmodeldef.con <- "

Group: 1

level: 1

Post ~ Pre_z + bg1*SR3.theta +math.fscores

level: 2

Post ~ Pre_z + math.fscores

Group: 2

level: 1

Post ~ Pre_z + bg2*SR3.theta + math.fscores

level: 2

Post ~ Pre_z + math.fscores

bg1 == bg2

"

fit.uncon <- sem(lavmodeldef.uncon, data = dta.ATI, cluster = "Lehrperson", estimator="MLR",group="Gruppe")

fit.con <- sem(lavmodeldef.con, data = dta.ATI, cluster = "Lehrperson", estimator="MLR",group="Gruppe")

lavTestLRT(fit.uncon, fit.con)

---END OF CODE----

unfortunately, for me, both versions have p-values of around .99, so no significant difference (this interpretation is correct, isn't it?)

Thanks all the same, maybe the code is useful for somebody.

Kind regards, Martin

Reply all

Reply to author

Forward

0 new messages

Search

Clear search

Close search

Google apps

Main menu