# The goal of moderator analysis in metaSEM::wls()

14 posts / 0 new
Offline
Joined: 07/31/2023 - 13:19
The goal of moderator analysis in metaSEM::wls()

Dear Mike and Colleagues,

My understanding is that moderator analysis at the 2nd stage of metaSEM approach using metaSEM::wls() involves multi-group analysis.

Thus, as a user I have to subset my data by categories of my moderator, and fit the same model syntax to each subset as shown below.

But at the end, how can I conclude whether I have a significant moderator or not? For example, should/can I do: anova(wls1, wls2) and if one model is significantly different from another conclude that the moderator is significant? (I appreciate a demonstration.)

library(metaSEM)

## Sample sizes
n1 <- 100
n2 <- 200

## Variable labels
vars <- c("y", "x1", "x2")

## Group 1 data and model
R1 <- matrix(c(1.00, 0.22, 0.24,
0.22, 1.00, 0.30,
0.24, 0.30, 1.00), ncol=3, nrow=3,
dimnames=list(vars, vars))
acov1 <- asyCov(R1, n1)

model1 <- "y ~ b1a*x1 + b2a*x2
## Variances of x1 and x2 are 1
x1 ~~ 1*x1
x2 ~~ 1*x2
## x1 and x2 are correlated
x1 ~~ ra*x2"

RAM1 <- lavaan2RAM(model1, obs.variables=vars)

wls1 <- wls(model="Group1", Cov=R1, aCov=acov1, n=n1, RAM=RAM1)

## Group 2 data and model
R2 <- matrix(c(1.00, 0.33, 0.41,
0.33, 1.00, 0.35,
0.41, 0.35, 1.00), ncol=3, nrow=3,
dimnames=list(vars, vars))
acov2 <- asyCov(R2, n2)

model2 <- "y ~ b1b*x1 + b2b*x2
## Variances of x1 and x2 are 1
x1 ~~ 1*x1
x2 ~~ 1*x2
## x1 and x2 are correlated
x1 ~~ rb*x2"

RAM2 <- lavaan2RAM(model2, obs.variables=vars)

wls2 <- wls(model="Group2", Cov=R2, aCov=acov2, n=n2, RAM=RAM2)
Offline
Joined: 10/08/2009 - 22:37
wls() was not decided for

wls() was not decided for moderator analysis. osmasem() is a better option.

Offline
Joined: 07/31/2023 - 13:19
Dear Mike,

Dear Mike,

Sure, but I asked this to clarify your comment HERE. In that comment, what is the purpose behind creating a combined model like: mxModel(model="combined", wls1, wls2, mxFitFunctionMultigroup(c("Group1", "Group2")))? What do the statistics of this combined model tell us about the moderatory role of "Group"?

In fact, as I ask in this thread, if the path models are exactly the same across two subsets of data, and we fit wls(...,run=F) for each model, then is it possible to compare the two models using mxModel(..., mxFitFunctionMultigroup(...)) and then mxRun()? I really appreciate a demonstration.

Offline
Joined: 10/08/2009 - 22:37
The purpose is to conduct a

The purpose is to conduct a subgroup analysis in meta-analysis, which is equivalent to a multiple-group analysis in SEM.

The models with equality constraints and without equality constraints are nested. Thus, a chi-square difference statistic can be used to compare them.

There are plenty of resources for subgroup analysis in meta-analysis and multiple-group SEM. Here are some materials for a three-day workshop in MASEM. https://github.com/mikewlcheung/masemWorkshop2023

Offline
Joined: 07/31/2023 - 13:19
Dear Mike,

Dear Mike,

Is it possible to conduct pairwise comparisons between the elements of A.matrix and S.matrix from the two groups in the object output below?

## Sample sizes
n1 <- 100
n2 <- 200

## Variable labels
vars <- c("y", "x1", "x2")

## Group 1 data and model
R1 <- matrix(c(1.00, 0.22, 0.24,
0.22, 1.00, 0.30,
0.24, 0.30, 1.00), ncol=3, nrow=3,
dimnames=list(vars, vars))
acov1 <- asyCov(R1, n1)

model1 <- "y ~ b1a*x1 + b2a*x2
## Variances of x1 and x2 are 1
x1 ~~ 1*x1
x2 ~~ 1*x2
## x1 and x2 are correlated
x1 ~~ ra*x2"

## Group 2 data but model is the same as model1
R2 <- matrix(c(1.00, 0.33, 0.41,
0.33, 1.00, 0.35,
0.41, 0.35, 1.00), ncol=3, nrow=3,
dimnames=list(vars, vars))
acov2 <- asyCov(R2, n2)

model2 <- "y ~ b1b*x1 + b2b*x2
## Variances of x1 and x2 are 1
x1 ~~ 1*x1
x2 ~~ 1*x2
## x1 and x2 are correlated
x1 ~~ rb*x2"

RAM1 <- lavaan2RAM(model1, obs.variables=vars)
RAM2 <- lavaan2RAM(model2, obs.variables=vars)

wls1 <- wls(model="Group1", Cov=R1, aCov=acov1, n=n1, RAM=RAM1, run=F)
wls2 <- wls(model="Group2", Cov=R2, aCov=acov2, n=n2, RAM=RAM2, run=F)

## Combine both groups
wls.model <- mxModel(model="combined", wls1, wls2, mxFitFunctionMultigroup(c("Group1", "Group2")))

wls.fit <- mxRun(wls.model, intervals=TRUE)

zz = summary(wls.fit)

(output = cbind(zz$parameters[-c(3:4,7:10)], zz$CI[c("lbound","ubound")]))

name         matrix  Estimate  Std.Error       lbound    ubound
1  b1a Group1.Amatrix 0.1626374 0.09928458 -0.034465926 0.3598924
2  b2a Group1.Amatrix 0.1912088 0.09881592 -0.004306087 0.3874504
3   ra      Group1.S1 0.3000000 0.09100000  0.120857208 0.4785835
4  b1b Group2.Amatrix 0.2125356 0.06601287  0.082020597 0.3433026
5  b2b Group2.Amatrix 0.3356125 0.06395664  0.209506797 0.4626121
6   rb      Group2.S1 0.3500000 0.06204862  0.228300669 0.4720198
Offline
Joined: 10/08/2009 - 22:37
Yes, but it is not automatic.

Yes, but it is not automatic.
You may test the constraints one by one, e.g., b1a=b1b, b2a=b2b. Please note that it does not adjust the issue of multiple comparisons.

Offline
Joined: 07/31/2023 - 13:19
Thank you, Mike. Can you

Thank you, Mike. Can you possibly demonstrate testing only one such constraint to help figure out the process?

Offline
Joined: 10/08/2009 - 22:37
Here is an example.

Here is an example.

model1 <- "y ~ b1*x1 + b2a*x2
## Variances of x1 and x2 are 1
x1 ~~ 1*x1
x2 ~~ 1*x2
## x1 and x2 are correlated
x1 ~~ ra*x2"

model2 <- "y ~ b1*x1 + b2b*x2
## Variances of x1 and x2 are 1
x1 ~~ 1*x1
x2 ~~ 1*x2
## x1 and x2 are correlated
x1 ~~ rb*x2"

RAM1 <- lavaan2RAM(model1, obs.variables=vars)
RAM2 <- lavaan2RAM(model2, obs.variables=vars)

wls1 <- wls(model="Group1", Cov=R1, aCov=acov1, n=n1, RAM=RAM1, run=F)
wls2 <- wls(model="Group2", Cov=R2, aCov=acov2, n=n2, RAM=RAM2, run=F)

## Combine both groups
wls.b1 <- mxModel(model="b1", wls1, wls2, mxFitFunctionMultigroup(c("Group1", "Group2")))
fit.b1 <- mxRun(wls.b1, intervals=TRUE)

summary(fit.b1)

anova(wls.fit, fit.b1)
Offline
Joined: 07/31/2023 - 13:19
Truly appreciated, Mike. Just

Truly appreciated, Mike. Just curious, given that estimates from each group use independent pieces of data, can't we compute the standard error of their coefficients' differences e.g., SE(b1a - b1b = 0) by doing SE_dif = SQRT(SE_b1a^2 + SE_b1b^2) assuming near-normally distributed sampling distribution for b1a - b1b?

If yes, then H0: b1a - b1b = 0, may be tested with standard wald-type, Z-test.

Offline
Joined: 10/08/2009 - 22:37
Yes, you can choose between

Yes, you can choose between the likelihood ratio and Wald tests.

Offline
Joined: 07/31/2023 - 13:19
Final confirmation, can Wald

Final confirmation, can Wald tests be applied both to the elements of A.matrix and S.matrix from the two groups?

Also, are there any references (papers, book chapters etc.) discussing the use of Wald tests in the manner that I suggested in my previous post for comparing across the estimates from independent groups?

Offline
Joined: 10/08/2009 - 22:37
Wald test can be applied to

Wald test can be applied to both A and S matrices.

You may refer to the literature of multiple group SEM.

Offline
Joined: 07/31/2023 - 13:19
Dear Mike,

Dear Mike,

Is there any way to convert a wls() object with run=TRUE or run=FALSE to a corresponding lavaan object?

Offline
Joined: 10/08/2009 - 22:37
I am afraid not because this

I am afraid not because this functionality is not available in lavaan.