# How to estimate correlations between weighted composites of observed variables from correlation matrix using lavaan?

I'm currently doing a meta-analysis where I often have correlation matrices for a set of variables. A common scenario is that a study has reported a correlation matrix for the criteria (e.g., dv) and a set of predictors (e.g., x1, x2, y1, y2). Now it's also common to create a unit weighted composite of the predictors. i.e., x = x1 + x2; y = y1 + y2. And I would like to know the correlation between this composites and the criteria (and more generally the full correlation matrix of composites, predictors, and criteria). But the paper has not reported the correlations for the composites. As I understand it, it should be possible to calculate this correlation.

I have been trying to use lavaan for this purpose. I assume that it would be possible to specify the model.

I have generated sample data with a known correlation matrix to verify whether the solution is accurate:

Here is some simulated data:

set.seed(1234)
n = 1000
simdata <- data.frame(x = rnorm(n), y = rnorm(n))
simdata$$x1 <- simdata$$x + rnorm(n)
simdata$$x2 <- simdata$$x + rnorm(n)
simdata$$x <-simdata$$x1 + simdata$$x2 simdata$$y1 <- simdata$$y + rnorm(n) + 0.3 * simdata$$x # often predictors are a little correlated
simdata$$y2 <- simdata$$y + rnorm(n) + 0.3 * simdata$$x # often predictors are a little correlated simdata$$y <-simdata$$y1 + simdata$$y2
simdata$$dv <- 2 * simdata$$x + simdata\$y + rnorm(n)
simcor <- cor(simdata)# The correlation with all variables
remdata <- simdata[,setdiff(names(simdata), c("x", "y"))]
remcor <- cor(remdata) # correlation matrix with the composites removed


So here is the full correlation matrix (simcor):

       x     y    x1    x2    y1    y2    dv
x  1.000 0.540 0.868 0.862 0.474 0.499 0.927
y  0.540 1.000 0.458 0.476 0.901 0.901 0.792
x1 0.868 0.458 1.000 0.496 0.403 0.423 0.802
x2 0.862 0.476 0.496 1.000 0.418 0.440 0.802
y1 0.474 0.901 0.403 0.418 1.000 0.625 0.703
y2 0.499 0.901 0.423 0.440 0.625 1.000 0.725
dv 0.927 0.792 0.802 0.802 0.703 0.725 1.000


And here is the reduced correlation matrix (remcor)

      x1    x2    y1    y2    dv
x1 1.000 0.496 0.403 0.423 0.802
x2 0.496 1.000 0.418 0.440 0.802
y1 0.403 0.418 1.000 0.625 0.703
y2 0.423 0.440 0.625 1.000 0.725
dv 0.802 0.802 0.703 0.725 1.000


My aim is to use lavaan (or another tool) to recover the complete correlation matrix from the reduced correlation matrix, knowing that x = x1 + x2 and y = y1 + y2.

Here is what I've tried:

script <-c("
x <~ 1 * x1 + 1 * x2
y <~ 1 * y1 + 1 * y2
dv ~~ x + y
x ~~ y
" )

fit <- sem(script, sample.cov = remcor, sample.nobs = nrow(remdata))
semcor <- unclass(inspect(fit, "cor.all")) # extract implied and observed correlation matrix
semcor <- semcor[row.names(simcor), row.names(simcor)] # reorder
round(semcor - simcor, 3) # compare estimated and actual correlations


Essentially, the script creates two computed variables x and y and says that x, y, and dv should be allowed to correlate.

It produces the following discrepency:

        x      y     x1     x2     y1     y2     dv
x   0.000  0.000 -0.003  0.003  0.000  0.000 -0.927
y   0.000  0.000  0.000  0.000  0.000  0.000 -0.792
x1 -0.003  0.000  0.000  0.000  0.000  0.000 -0.802
x2  0.003  0.000  0.000  0.000  0.000  0.000 -0.802
y1  0.000  0.000  0.000  0.000  0.000  0.000 -0.703
y2  0.000  0.000  0.000  0.000  0.000  0.000 -0.725
dv -0.927 -0.792 -0.802 -0.802 -0.703 -0.725  0.000


In summary, it seems to be working except for the criteria.

When running sem, it also throws up a warning:

In lav_model_vcov(lavmodel = lavmodel, lavsamplestats = lavsamplestats, :

  lavaan WARNING:
Could not compute standard errors! The information matrix could
not be inverted. This may be a symptom that the model is not
identified.


I wonder how one would fix this and get general reliable estimation of these correlations of composites.

## 1 Answer

After a little further experimentation, the following script seems to remove the discrepancy:

script <-c("
x <~ 1 * x1 + 1 * x2
y <~ 1 * y1 + 1 * y2
x ~ dv
y ~ dv
" )

fit <- sem(script, sample.cov = remcor, sample.nobs = nrow(remdata),
se = "none")
semcor <- unclass(inspect(fit, "cor.all"))


Checking this with the following

semcor <- semcor[row.names(simcor), row.names(simcor)] # reorder
round(semcor - simcor, 3) # compare estimated and actual correlations


Yields the following discrepancy between actual and estimated correlations:

        x y     x1    x2 y1 y2 dv
x   0.000 0 -0.003 0.003  0  0  0
y   0.000 0  0.000 0.000  0  0  0
x1 -0.003 0  0.000 0.000  0  0  0
x2  0.003 0  0.000 0.000  0  0  0
y1  0.000 0  0.000 0.000  0  0  0
y2  0.000 0  0.000 0.000  0  0  0
dv  0.000 0  0.000 0.000  0  0  0


It seems that the remaining discrepancy is caused by the use of the correlation matrix rather than the covariance matrix. Effectively, the weighting on the correlations is like doing weights on z-scores of the variables rather than the raw variables. I.e., in the raw data, the variances of the raw variables will influence their impact on the composite.

If you provide the covariance matrix rather than the correlation matrix to lavaan, this issue is removed. Alternatively, you can adjust the weights. And in many contexts to control for differential variances; Finally, often it is simpler to think about weights in terms of z-score variables.