SEM using correlation matrix in lavaan

143 views
Skip to first unread message

Asghar Minaei

unread,
Sep 25, 2026, 4:08:49 PMSep 25
to lavaan
Hello everyone,

I have a question regarding conducting confirmatory factor analysis (CFA) in lavaan using a correlation matrix rather than a covariance matrix.

I am aware that lavaan allows a correlation matrix to be supplied as input through the "sample.cov" argument. However, my question concerns the statistical implications of doing so.

I have a correlation matrix and would like to fit a three-factor CFA model to it. In some sources, and particularly in Rex B. Kline(2023, p. 141), it is stated that conducting CFA or structural equation modeling based on a correlation matrix requires imposing nonlinear constraints manually. The rationale seems to be related to the fact that a correlation matrix has standardized variances and therefore does not contain the original variance information.

I would therefore like to ask:

1. Is it statistically appropriate to fit a CFA model directly to a correlation matrix in lavaan by specifying it through "sample.cov"?
2. If so, does lavaan automatically handle the implications of using a correlation matrix, or are additional constraints or adjustments required?
3. What exactly does Kline mean by the statement that nonlinear constraints need to be imposed when CFA/SEM is based on a correlation matrix?
4. Are there any references, papers, or examples that discuss this issue specifically in relation to lavaan?

I would be very grateful for any clarification or references, particularly from those who have experience with CFA/SEM based on correlation matrices.

Thank you in advance for your help.
AsgharScreenshot (1785).png


Yves Rosseel

unread,
Sep 27, 2026, 4:23:30 AMSep 27
to lav...@googlegroups.com
For the analysis of correction structures, you need to add the
'correlation = TRUE' option. lavaan then treats the input matrix
(provided by sample.cov=) as a correlation matrix, and will provide
correct standard errors and test statistics.

(lavCor() has nothing to do with this)

Yves.

Asghar Minaei

unread,
Sep 28, 2026, 3:28:19 AMSep 28
to lavaan
Dear Yves,

Thank you very much for taking the time to answer my question. Following your suggestion, I tried to analyze the correlation matrix reported in Section 3 of Table 1 (p. 321) of the Cudeck (1989) article using the code below:

Screenshot (1789).png

However, lavaan returned the following error message:

Screenshot (1788).png

Could you please let me know where the problem is in my code and how I should modify it to correctly analyze the correlation matrix using `correlation = TRUE`?

Thank you again for your response and for your help. 
Best,
Asghar
Cudeck1989_Analysis of Correlation Matrices Using Covariance Structure Models.pdf

balal izanloo

unread,
Sep 28, 2026, 4:31:30 AMSep 28
to lav...@googlegroups.com
greatrings
you have specified one value in the diagonal of the matrix wrongly 1.46 should be .46. so it work for me

corm <- matrix(c(1.00,  .44, .41 ,.29, .33, .25,
.44,  1.00, .35, .35, .32, .33,
.41,  .35,  1.00, .16, .19, .18,  
.29,  .35,  .16,  1.00, .59, .47,
.33,  .32,  .19,  .59,   1.00, .46,
.25,  .33,  .18,  .47,   .46,  1.00), nrow=6, byrow=T)

colnames(corm) <- rownames(corm)  <- c("French","English","History","Arithmetic","Algebra","Geometry")
corm

mod <-  "F1=~ French+English+History
         F2=~ Arithmetic+Algebra+Geometry"
res <- lavaan::cfa(mod, sample.cov=corm, sample.nobs=220, std.lv=T, correlation=T)
print(res)

--
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 visit https://groups.google.com/d/msgid/lavaan/f84c536a-aa04-409f-9983-6e8ca1a41cadn%40googlegroups.com.

balal izanloo

unread,
Sep 28, 2026, 4:36:22 AMSep 28
to lav...@googlegroups.com
greatrings
you have specified one value in the diagonal of the matrix wrongly 1.46 should be .46. so it work for me

corm <- matrix(c(1.00,  .44, .41 ,.29, .33, .25,
.44,  1.00, .35, .35, .32, .33,
.41,  .35,  1.00, .16, .19, .18,  
.29,  .35,  .16,  1.00, .59, .47,
.33,  .32,  .19,  .59,   1.00, .46,
.25,  .33,  .18,  .47,   .46,  1.00), nrow=6, byrow=T)

colnames(corm) <- rownames(corm)  <- c("French","English","History","Arithmetic","Algebra","Geometry")
corm

mod <-  "F1=~ French+English+History
         F2=~ Arithmetic+Algebra+Geometry"
res <- lavaan::cfa(mod, sample.cov=corm, sample.nobs=220, std.lv=T, correlation=T)
lavaan::summary(res, fit=TRUE, ci=TRUE, nd=3)


On Mon, Sep 28, 2026 at 10:58 AM Asghar Minaei <asghar...@gmail.com> wrote:

Asghar Minaei

unread,
Sep 28, 2026, 5:05:52 AMSep 28
to lav...@googlegroups.com
Thank you very much for your careful attention and for pointing this out. I made the correction, and the analysis worked for me as well.
However, the main issue is that the standard errors and the chi-square value I obtain are different from those reported in Table 4 of Cudeck (1989).
I am trying to understand the reason for this discrepancy and whether there is an additional option or specification that needs to be used in lavaan to reproduce Cudeck's result

balal izanloo

unread,
Sep 28, 2026, 5:31:35 AMSep 28
to lav...@googlegroups.com

compare previous results with new one (based on correlation as cov matrix not cor matrix). The difference between the results of the two methods amounts to a few decimal places, and at times, they are identical. Of course, incorporating the views of other group members is also beneficial.


rescov <- lavaan::cfa(mod, sample.cov=corm, sample.nobs=220, std.lv=T, correlation=F)
print(rescov)
lavaan::summary(rescov, fit=TRUE, ci=TRUE, nd=3)


Edward Rigdon

unread,
Sep 28, 2026, 6:47:23 AMSep 28
to lav...@googlegroups.com
What package did Cudeck report using? Different SEM packages use different optimization approaches. Some packages are optimized for strictly correct models while other packages are optimized assuming that models will typically have small discrepancies. If the chi-square for this model is not exactly 0, then I might expect some small differences between solutions, even though both packages relied upon "maximum likelihood" estimation. I believe that lavaan allows you to alter the precision of its optimizer--how much of a change in values from iteration to iteration amounts to a meaningful improvement. You might try changing that (no, I have never felt the need) to see whether your results come closer to those that Cudeck reported.

Yves Rosseel

unread,
Sep 29, 2026, 6:30:58 AMSep 29
to lav...@googlegroups.com
Use likelihood = "wishart" (which will invoke the N-1 multiplier that
was likely used at the time):

lavaan 0.7-2.3262 ended normally after 19 iterations

Estimator ML
Optimization method NLMINB
Number of model parameters 13

Number of observations 220

Model Test User Model:

Test statistic 7.918
Degrees of freedom 8
P-value (Chi-square) 0.442

Browne's residual (NT model-based) test
Test statistic 8.054
Degrees of freedom 8
P-value (Chi-square) 0.428

Parameter Estimates:

Standard errors Standard
Information Expected
Information saturated (h1) model Structured

Latent Variables:
Estimate Std.Err z-value P(>|z|)
f1 =~
fr (L01) 0.690 0.059 11.657 0.000
en (L02) 0.671 0.060 11.273 0.000
hi (L03) 0.531 0.064 8.250 0.000
f2 =~
ar (L04) 0.764 0.046 16.581 0.000
al (L05) 0.764 0.046 16.572 0.000
ge (L06) 0.616 0.053 11.601 0.000

Covariances:
Estimate Std.Err z-value P(>|z|)
f1 ~~
f2 0.598 0.072 8.322 0.000

Variances:
Estimate Std.Err z-value P(>|z|)
.fr (T01) 0.524
.en (T02) 0.550
.hi (T03) 0.718
.ar (T04) 0.416
.al (T05) 0.416
.ge (T06) 0.620
f1 1.000
f2 1.000

Scaling Parameters:
Estimate Std.Err z-value P(>|z|)
fr 1.000 0.048 20.928 0.000
en 1.000 0.048 20.928 0.000
hi 1.000 0.048 20.928 0.000
ar 1.000 0.048 20.928 0.000
al 1.000 0.048 20.928 0.000
ge 1.000 0.048 20.928 0.000




Yves.
> <http://std.lv>=T, correlation=T)
> lavaan::summary(res, fit=TRUE, ci=TRUE, nd=3)
>
>
> On Mon, Sep 28, 2026 at 10:58 AM Asghar Minaei
> <asghar...@gmail.com <mailto:asghar...@gmail.com>> wrote:
>
> Dear Yves,
>
> Thank you very much for taking the time to answer my question.
> Following your suggestion, I tried to analyze the correlation
> matrix reported in Section 3 of Table 1 (p. 321) of the Cudeck
> (1989) article using the code below:
>
> Screenshot (1789).png
>
> However, lavaan returned the following error message:
>
> Screenshot (1788).png
>
> Could you please let me know where the problem is in my code and
> how I should modify it to correctly analyze the correlation
> matrix using `correlation = TRUE`?
>
> Thank you again for your response and for your help.
> Best,
> Asghar
>
>
> On Sunday, 27 September 2026 at 11:53:30 UTC+3:30
> yros...@gmail.com <mailto:yros...@gmail.com> wrote:
>
> For the analysis of correction structures, you need to add the
> 'correlation = TRUE' option. lavaan then treats the input
> matrix
> (provided by sample.cov=) as a correlation matrix, and will
> provide
> correct standard errors and test statistics.
>
> (lavCor() has nothing to do with this)
>
> Yves.
>
> --
> 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
> <mailto:lavaan+un...@googlegroups.com>.
> To view this discussion visit https://groups.google.com/d/msgid/
> lavaan/f84c536a-aa04-409f-9983-6e8ca1a41cadn%40googlegroups.com
> <https://groups.google.com/d/msgid/lavaan/f84c536a-
> aa04-409f-9983-6e8ca1a41cadn%40googlegroups.com?
> utm_medium=email&utm_source=footer>.
>
> --
> 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
> <mailto:lavaan+un...@googlegroups.com>.
> To view this discussion visit https://groups.google.com/d/msgid/
> lavaan/
> CAKpMYbKuY0f9L9n7yU8x_S%3Dk1zANd7rijYSKQkb5vzN2ZWyRtA%40mail.gmail.com <https://groups.google.com/d/msgid/lavaan/CAKpMYbKuY0f9L9n7yU8x_S%3Dk1zANd7rijYSKQkb5vzN2ZWyRtA%40mail.gmail.com?utm_medium=email&utm_source=footer>.
>
> --
> 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
> <mailto:lavaan+un...@googlegroups.com>.
> To view this discussion visit https://groups.google.com/d/msgid/lavaan/
> CA%2BGx8K_-2vBYfbuG7%2BVWr5%2B%3DcoJBipozBQRNcpXdqQDrTuUWxQ%40mail.gmail.com <https://groups.google.com/d/msgid/lavaan/CA%2BGx8K_-2vBYfbuG7%2BVWr5%2B%3DcoJBipozBQRNcpXdqQDrTuUWxQ%40mail.gmail.com?utm_medium=email&utm_source=footer>.

Asghar Minaei

unread,
Oct 1, 2026, 12:47:44 AMOct 1
to lav...@googlegroups.com
Dear Yves,

Thank you very much for your helpful response and for explaining the use of likelihood = "wishart". I also greatly appreciate the improvements you made in the new version(0.7.2.3257) of lavaan. With the new version of lavaan and the following code, we were able to reproduce the results reported in Table 4 of Cudeck (1989) exactly:

mod_5 = '
     #loadings of MVs on LVs
      f1 =~ L01*fr + L02*en + L03*hi
      f2 =~ L04*ar + L05*al + L06*ge

     #unique variances
     # these theta estimates have been deleted
     #factor variances and covariances
      f1 ~~ 1*f1           # fix LV variance at 1.0
      f2 ~~   f1 + 1*f2
      '
m5fit = lavaan(model = mod_5, meanstructure = FALSE,
               std.lv = TRUE, auto.fix.first = FALSE,
               sample.cov = cor1, sample.nobs = 220,
               likelihood = 'wishart',
               estimator  = 'ML',
               correlation = TRUE)

The parameter estimates, standard errors, and ML chi-square now match the corresponding results reported by Cudeck. However, we have encountered one remaining issue. lavaan provides the point estimates of the unique variances, but it does not appear to provide their standard errors. The standard errors of the unique variances are reported in Table 4 of Cudeck's article. I would be very grateful if you could help me understand why lavaan does not produce the standard errors for the unique variances and whether there is a way to obtain them.
Best,
Asghar


To unsubscribe from this group and stop receiving emails from it, send an email to lavaan+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/lavaan/f3b73b99-9959-4f55-a497-0d021254eff1%40gmail.com.

Yves Rosseel

unread,
Oct 1, 2026, 3:44:42 AMOct 1
to lav...@googlegroups.com
> lavaan provides the point estimates of
> the unique variances, but it does not appear to provide their standard
> errors. The standard errors of the unique variances are reported in
> Table 4 of Cudeck's article.
The unique variances are no longer free parameters. They are a
(deterministic) function of the other parameters. In principle, one
could use the delta rule to compute standard errors for these 'defined'
parameters (as we do with the := operator), but lavaan does not do that
out of the box.

So if you really want them, you need to define them explicitly using the
:= operator. In this case, they are easy. The model-implied variance per
item is just lambda squared, as the variance of the latent variable is
fixed to one, so we have:

model <- '
#loadings of MVs on LVs
f1 =~ L01*fr + L02*en + L03*hi
f2 =~ L04*ar + L05*al + L06*ge

#factor variances and covariances
f1 ~~ 1*f1
f2 ~~ 1*f2
f2 ~~ f1

resvar.fr := 1 - L01^2
resvar.en := 1 - L02^2
resvar.hi := 1 - L03^2
resvar.ar := 1 - L04^2
resvar.al := 1 - L05^2
resvar.ge := 1 - L06^2
'

fit = lavaan(model = model, correlation = TRUE, likelihood = "wishart",
sample.cov = cor1, sample.nobs = 220)

resulting in:

lavaan 0.7-2.3265 ended normally after 19 iterations
f1 1.000
f2 1.000
.fr 0.524
.en 0.550
.hi 0.718
.ar 0.416
.al 0.416
.ge 0.620

Scaling Parameters:
Estimate Std.Err z-value P(>|z|)
fr 1.000 0.048 20.928 0.000
en 1.000 0.048 20.928 0.000
hi 1.000 0.048 20.928 0.000
ar 1.000 0.048 20.928 0.000
al 1.000 0.048 20.928 0.000
ge 1.000 0.048 20.928 0.000

Defined Parameters:
Estimate Std.Err z-value P(>|z|)
resvar.fr 0.524 0.082 6.424 0.000
resvar.en 0.550 0.080 6.880 0.000
resvar.hi 0.718 0.068 10.496 0.000
resvar.ar 0.416 0.070 5.907 0.000
resvar.al 0.416 0.070 5.913 0.000
resvar.ge 0.620 0.065 9.478 0.000

lavaan NOTE:
Standard errors and confidence intervals of the (nonlinear) defined
(:=)
parameters are based on the first-order delta method; for strongly
nonlinear definitions, se_def = "mc" (Monte Carlo) or se =
"bootstrap" may
be more accurate.


I believe there may be an error in Table 4 of Cudeck's paper. Apart from
the double 'psi_2' label in the first column, the standard error for
psi_3 should be 0.068, not 0.080 (which is most likely a copy/paste error).


Yves.

Asghar Minaei

unread,
Oct 4, 2026, 3:19:05 AMOct 4
to lav...@googlegroups.com

Hi Yves,

Thank you very much for the clear explanation.

Best,

Asghar



--
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.
Reply all
Reply to author
Forward
0 new messages