> I was under the impression that the chi-squared value provided under ML
> estimation is calculated by multiplying the sample size (or N - 1 in
> LISREL) by the ML discrepancy function.
That is correct. Also in lavaan.
I'm also under the impression
> that the ML discrepancy function = -2LL (negative 2 times the
> log-likelihood), which is equal to the formula provided in many sources
> (e.g., Bollen, 1989; Browne & Cudeck, 1992):
>
> ML-discFunc = log( | Sigma-hat | ) - log( | S | ) + trace(S *
> inverse-Sigma-hat) - p
Not in lavaan, as you have observed.
There are many ways to compute a (log)likelihood. What lavaan is doing
is this: we simply calculate the (log)likelihood of the data, assuming a
multivariate normal distribution with Sigma equal to the model-implied
variance covariance matrix, and Mu equal to either the observed mean
vector (if meanstructure=FALSE) or the model-implied meanstructure (if
meanstructure=TRUE).
For example,
library(lavaan)
example(cfa)
fitMeasures(fit, "logl")
# logl
#-3737.745
Now, we need three components: the Data, the model-implied
variance/covariance matrix, and the (observed) mean vector:
Data <- HolzingerSwineford1939[,7:15]
Sigma <- unclass(fitted(fit)$cov)
Mean <- as.numeric(inspect(fit, "sampstat")$mean)
Using 'dmnorm' from the mnormt package to compute likelihoods under the
multivariate normal:
liks <- dmnorm(as.matrix(Data), mean=as.numeric(Mean), varcov=Sigma)
Taking logs, and sum over all N cases:
logl <- sum(log(liks))
# -3737.745
Now, suppose you compute the same logl under the unrestricted model
(using the observed variance-covariance matrix, and observed mean
vector), you get:
Sigma.obs <- unclass(inspect(fit, "sampstat")$cov)
Mean.obs <- as.numeric(inspect(fit, "sampstat")$mean)
liks.h1 <- dmnorm(as.matrix(Data), mean=as.numeric(Mean.obs),
varcov=Sigma.obs)
logl.h1 <- sum(log(liks.h1))
# -3695.092
Now take the difference between logl and logl.h1, and multiply by (-2):
-2 * (logl - logl.h1)
# 85.30552
confirming that the chi-squared statistic is indeed the likelihood ratio
statistic.
>>## using Bollen's (1989) formula for the discrepancy function
>> psi <- inspect(fit, "coef")$psi
>> lambda <- inspect(fit, "coef")$lambda
>> theta <- inspect(fit, "coef")$theta
>>
>> SigmaHat <- (lambda %*% psi %*% t(lambda)) + theta
>> S <- cov(HolzingerSwineford1939[ , paste0("x", 1:9)])
If likelihood="normal" (which is the default in lavaan), you need to use
S <- unclass(inspect(fit, "sampstat")$cov)
This will give you 85.30552 exactly
(the difference is that the internal version of S is rescaled by (N-1)/N
to make sure the covariance elements are divided by N, and not by N-1.
The ML estimator assumes N...
Hope this helps.
Yves.