Skip to contents

LRT test for comparing (nested) lavaan models.

Usage

lavTestLRT(object, ..., method = "default", test = "default",
           a_method = "delta", scaled_shifted = TRUE,
           type = "Chisq", model_names = NULL)
anova(object, ...)

Arguments

object

An object of class lavaan.

...

additional objects of class lavaan.

method

Character string. The possible options are "satorra.bentler.2001", "satorra.bentler.2010", "satorra.2000", and "standard". See details. Note that the robust options ("satorra.bentler.2001", "satorra.bentler.2010" and "satorra.2000") require that the models were fitted with a robust (scaled) test statistic (for example, using estimator = "MLM" or test = "satorra.bentler"). If none of the models were fitted with a robust test statistic, but a robust method= is requested, a warning is issued, the method= argument is ignored, and a standard (regular) chi-squared difference test is computed instead.

test

Character string specifying which scaled test statistics to use, in case multiple scaled test= options were requested when fitting the model(s). See details. FMG nested tests can be requested using names such as "pall", "all", "peba4", or "pols3"; the convenience value "fmg" resolves to the recommended nested default.

a_method

Character string. The possible options are "exact" and "delta". This is only used when method = "satorra.2000". It determines how the Jacobian of the constraint function (the matrix A) will be computed. Note that if a_method = "exact", the models must be nested in the parameter sense, while if a_method = "delta", they only need to be nested in the covariance matrix sense.

scaled_shifted

Logical. Only used when method = "satorra.2000". If TRUE, we use a scaled and shifted test statistic. If FALSE, the statistic depends on the test that was used to fit the models: when the models were fitted with a mean-and-variance adjusted test (test = "mean.var.adjusted" or "scaled_shifted"), a mean and variance adjusted (Satterthwaite style) difference test is used; when they were fitted with a (Satorra-)Bentler scaled test (test = "satorra.bentler", "yuan.bentler" or "yuan.bentler.mplus"), a scaled (non-shifted) difference test is used. The title printed above the anova table reflects the statistic that is actually used.

type

Character. If "Chisq", the test statistic for each model is the (scaled or unscaled) model fit test statistic. If "Cf", the test statistic for each model is computed by the lavTablesFitCf function. If "browne.residual.adf" (alias "browne") or "browne.residual.nt", the standard chi-squared difference is calculated from each model's residual-based statistic.

model_names

Character vector. If provided, use these model names in the first column of the anova table.

Value

An object of class anova. When given a single argument, it simply returns the test statistic of this model. When given a sequence of objects, this function tests the models against one another, after reordering the models according to their degrees of freedom.

Details

The anova function for lavaan objects simply calls the lavTestLRT function, which has a few additional arguments.

The only test= options that currently have actual consequences are "satorra.bentler", "yuan.bentler", or "yuan.bentler.mplus" because "mean.var.adjusted" and "scaled_shifted" are currently distinguished by the scaled_shifted argument. See lavOptions for details about the test= options implied by robust estimator= options. The "default" is to select the first available scaled statistic, if any. To check which test(s) were computed when fitting your model(s), use lavInspect(fit, "options")$test.

If type = "Chisq" and the test statistics are scaled, a special scaled difference test statistic is computed. If method is "satorra.bentler.2001", a simple approximation is used described in Satorra & Bentler (2001). In some settings, this can lead to a negative test statistic. To ensure a positive test statistic, we can use the method proposed by Satorra & Bentler (2010). Alternatively, when method="satorra.2000", the original formulas of Satorra (2000) are used. The latter is used for model comparison when ... contains additional (nested) models. Even when test statistics are scaled in object or ..., users may request the method="standard" test statistic, without a robust adjustment.

Conversely, a robust method= ("satorra.bentler.2001", "satorra.bentler.2010" or "satorra.2000") can only be applied when the models were fitted with a robust (scaled) test statistic. If none of the models in object or ... were fitted with a robust test statistic, a robust method= cannot be honored: in that case a warning is issued, the method= argument is ignored, and a standard (regular) chi-squared difference test is returned.

FMG nested tests are available when type = "Chisq" and test is an FMG test name. The supported nested FMG methods are "pall", "all", "peba" and "pols" variants. The convenience value "fmg" resolves to "pall_ug_rls" for single-group comparisons and "pall_ug_ml" for multiple-group comparisons. They use the Satorra (2000) UGamma projection; method may be left at "default" or set to "standard" or "satorra.2000". Other nested LRT methods are not used for FMG tests.

Note

If there is a lavaan model stored in object@external$h1.model, it will be added to ...

References

Satorra, A. (2000). Scaled and adjusted restricted tests in multi-sample analysis of moment structures. In Heijmans, R.D.H., Pollock, D.S.G. & Satorra, A. (eds.), Innovations in multivariate statistical analysis: A Festschrift for Heinz Neudecker (pp.233-247). London, UK: Kluwer Academic Publishers.

Satorra, A., & Bentler, P. M. (2001). A scaled difference chi-square test statistic for moment structure analysis. Psychometrika, 66(4), 507-514. doi:10.1007/BF02296192

Satorra, A., & Bentler, P. M. (2010). Ensuring positiveness of the scaled difference chi-square test statistic. Psychometrika, 75(2), 243-248. doi:10.1007/s11336-009-9135-y

Foldnes, N., Moss, J., & Gronneberg, S. (2024). Improved goodness of fit procedures for structural equation models. Structural Equation Modeling: A Multidisciplinary Journal, 1-13. doi:10.1080/10705511.2024.2372028

Foldnes, N., Gronneberg, S., & Moss, J. (2026). Penalized eigenvalue block averaging: Extension to nested model comparison and Monte Carlo evaluations. Behavior Research Methods, 58(4). doi:10.3758/s13428-026-02968-4

Examples

HS.model <- '
    visual  =~ x1 + b1*x2 + x3
    textual =~ x4 + b2*x5 + x6
    speed   =~ x7 + b3*x8 + x9
'
fit1 <- cfa(HS.model, data = HolzingerSwineford1939)
fit0 <- cfa(HS.model, data = HolzingerSwineford1939,
            orthogonal = TRUE)
lavTestLRT(fit1, fit0)
#> 
#> Chi-Squared Difference Test
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> fit1 24 7517.5 7595.3  85.305                                          
#> fit0 27 7579.7 7646.4 153.527     68.222 0.26875       3  1.026e-14 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


## When multiple test statistics are selected when the model is fitted,
## use the type= and test= arguments to select a test for comparison.

## refit models, requesting 6 test statistics (in addition to "standard")
t6.1 <- cfa(HS.model, data = HolzingerSwineford1939,
            test = c("browne.residual.adf","scaled.shifted","mean.var.adjusted",
                     "satorra.bentler", "yuan.bentler", "yuan.bentler.mplus"))
#> Warning: lavaan->lav_options_set():  
#>    observed.information for ALL test statistics is set to h1.
t6.0 <- cfa(HS.model, data = HolzingerSwineford1939, orthogonal = TRUE,
            test = c("browne.residual.adf","scaled.shifted","mean.var.adjusted",
                     "satorra.bentler", "yuan.bentler", "yuan.bentler.mplus"))
#> Warning: lavaan->lav_options_set():  
#>    observed.information for ALL test statistics is set to h1.

## By default (test="default", type="Chisq"), the first scaled statistic
## requested will be used. Here, that is "scaled.shifted"
lavTestLRT(t6.1, t6.0)
#> 
#> Scaled and Shifted Chi-Squared Difference Test (method = “satorra.2000”)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the 
#>    robust test that should be reported per model. A robust difference test is 
#>    a function of two standard (not robust) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     62.699 0.26875       3  1.558e-13 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## But even if "satorra.bentler" were requested first, method="satorra.2000"
## provides the scaled-shifted chi-squared difference test:
lavTestLRT(t6.1, t6.0, method = "satorra.2000")
#> 
#> Scaled and Shifted Chi-Squared Difference Test (method = “satorra.2000”)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the 
#>    robust test that should be reported per model. A robust difference test is 
#>    a function of two standard (not robust) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     62.699 0.26875       3  1.558e-13 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## == lavTestLRT(update(t6.1, test = "scaled.shifted"), update(t6.0, test = "scaled.shifted"))

## The mean- and variance-adjusted (Satterthwaite) statistic implies
## scaled_shifted = FALSE
lavTestLRT(t6.1, t6.0, method = "satorra.2000", scaled_shifted = FALSE)
#> 
#> Mean and Variance Adjusted Chi-Squared Difference Test (method = “satorra.2000”)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the 
#>    robust test that should be reported per model. A robust difference test is 
#>    a function of two standard (not robust) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     61.316 0.26805   2.875  2.479e-13 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

## Because "satorra.bentler" is not the first scaled test in the list,
## we MUST request it explicitly:
lavTestLRT(t6.1, t6.0, test = "satorra.bentler") # method="satorra.bentler.2001"
#> 
#> Scaled Chi-Squared Difference Test (method = “satorra.bentler.2001”)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the 
#>    robust test that should be reported per model. A robust difference test is 
#>    a function of two standard (not robust) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     55.899 0.26739       3  4.414e-12 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## == lavTestLRT(update(t6.1, test = "satorra.bentler"),
##               update(t6.0, test = "satorra.bentler"))
## The "strictly-positive test" is necessary when the above test is < 0:
lavTestLRT(t6.1, t6.0, test = "satorra.bentler", method = "satorra.bentler.2010")
#> 
#> Scaled Chi-Squared Difference Test (method = “satorra.bentler.2010”)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the 
#>    robust test that should be reported per model. A robust difference test is 
#>    a function of two standard (not robust) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     55.326 0.26731       3  5.851e-12 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

## Likewise, other scaled statistics can be selected:
lavTestLRT(t6.1, t6.0, test = "yuan.bentler")
#> 
#> Scaled Chi-Squared Difference Test (method = “satorra.bentler.2001”)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the 
#>    robust test that should be reported per model. A robust difference test is 
#>    a function of two standard (not robust) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     55.899 0.26739       3  4.414e-12 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## == lavTestLRT(update(t6.1, test = "yuan.bentler"),
##               update(t6.0, test = "yuan.bentler"))
lavTestLRT(t6.1, t6.0, test = "yuan.bentler.mplus")
#> 
#> Scaled Chi-Squared Difference Test (method = “satorra.bentler.2001”)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the 
#>    robust test that should be reported per model. A robust difference test is 
#>    a function of two standard (not robust) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     66.195 0.26856       3  2.785e-14 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## == lavTestLRT(update(t6.1, test = "yuan.bentler.mplus"),
##               update(t6.0, test = "yuan.bentler.mplus"))

## To request the difference between Browne's (1984) residual-based statistics,
## rather than statistics based on the fitted model's discrepancy function,
## use the type= argument:
lavTestLRT(t6.1, t6.0, type = "browne.residual.adf")
#> 
#> Chi-Squared Difference Test based on Browne's residual (ADF) Test
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  82.408                                          
#> t6.0 27 7579.7 7646.4 106.942     24.534 0.15443       3  1.932e-05 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

## Despite requesting multiple robust tests, it is still possible to obtain
## the standard chi-squared difference test (i.e., without a robust correction)
lavTestLRT(t6.1, t6.0, method = "standard")
#> 
#> Chi-Squared Difference Test
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> t6.1 24 7517.5 7595.3  85.305                                          
#> t6.0 27 7579.7 7646.4 153.527     68.222 0.26875       3  1.026e-14 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## == lavTestLRT(update(t6.1, test = "standard"), update(t6.0, test = "standard"))

## FMG nested p-values use the Satorra (2000) UGamma projection
lavTestLRT(fit1, fit0, method = "satorra.2000", test = "pall")
#> 
#> FMG Chi-Squared Difference Test (PALL; base: ML, gamma: biased)
#> 
#> lavaan->lavTestLRT():  
#>    lavaan NOTE: The “Chisq” column contains standard test statistics, not the
#>    FMG test that should be reported per model. An FMG difference test is a
#>    function of two standard (not FMG) statistics.
#> 
#>      Df    AIC    BIC   Chisq Chisq diff   RMSEA Df diff Pr(>Chisq)    
#> fit1 24 7517.5 7595.3  85.305                                          
#> fit0 27 7579.7 7646.4 153.527     40.588 0.26875       3  7.997e-09 ***
#> ---
#> Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1