Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lav_test_print() skips $stat.group when NULL #363

Merged
merged 10 commits into from
Jun 20, 2024

Conversation

TDJorgensen
Copy link
Contributor

When I added lav_update_test_custom_h1() in PR #328, I set $stat.group <- NULL because when there is a more restricted h1.model=, the updated test is only available for the whole model. This causes an error when lav_test_printing multigroup models that have a hidden @external$h1.model.

HS.model <- '
    visual  =~ x1 + x2 + x3
    textual =~ x4 + x5 + x6
    speed   =~ x7 + x8 + x9
'
fit1 <- cfa(HS.model, data = HolzingerSwineford1939, group = "school")
fit0 <- cfa(HS.model, data = HolzingerSwineford1939, group = "school", 
            orthogonal = TRUE)
fit0@external$h1.model <- fit1
fit1 # prints group stats
fit0 # no group stats found, error

So I just added an additional condition in lav_test_print() to only print group stats if (ngroups > 1L && !is.null(TEST[[block]]$stat.group)).

@TDJorgensen
Copy link
Contributor Author

The second commit avoids an error due to the @test$satorra.bentler$scaling.factor set to NA when the user's h1.model fits perfectly. The commit message ends "df==0", but it should have said "$stat==0"

@TDJorgensen
Copy link
Contributor Author

Something strange is going on that I need time to track down. Please don't merge this PR yet.

@TDJorgensen
Copy link
Contributor Author

OK, this PR is ready now. Weirdly, the last issue was hard to track down, because it had nothing to do with the lav_test_update_custom_h1() function I made in April. There was an issue with running lavTestLRT() on a single model when multiple test= options were specified, in which case the hidden single_model function still did the old behavior of selecting the second @test element whenever there was one. So I added arguments or lavTestLRT() to pass, which retain the ability to select specific tests.

HS.model <- '
    visual  =~ x1 + x2 + x3
    textual =~ x4 + x5 + x6
    speed   =~ x7 + x8 + x9
'
TESTS <- c("satorra.bentler","scaled.shifted","browne.residual.adf")
fit1 <- cfa(HS.model, data = HolzingerSwineford1939, group = "school",
            test = TESTS)
fit0 <- cfa(HS.model, data = HolzingerSwineford1939, group = "school", 
            test = TESTS, orthogonal = TRUE)
fit0@external$h1.model <- fit1
fit0 # no more error!

I wrote a function to compare the @test slot (which does not adjust for a custom H1 model) to the short summary output that does adjust, followed by calling lavTestLRT() for each test to verify that summary() shows all the right stats.

checkTests  <- function(obj) {
  cat("UNCORRECTED:\n\n")
  lavaan:::lav_test_print(obj@test, nd = 5)

  cat("\n\nCORRECTED:\n\n")
  print(summary(obj, nd = 5, estimates = FALSE))

  cat("\n\nSTANDARD\n")
  print(lavTestLRT(obj, method = "standard"))

  cat("\n\nSCALED\n")
  sb <- lavTestLRT(obj, test = "satorra.bentler")
  print(sb)
  print(c(scale = attr(sb, "scale")[-1]))

  cat("\n\nSCALED and SHIFTED\n")
  sh <- lavTestLRT(obj, test = "scaled.shifted")
  print(sh)
  print(c(scale = attr(sh, "scale")[-1], shift = attr(sh, "shift")[-1]))

  cat("\n")
  print(lavTestLRT(obj, type = "browne.residual.adf"))
  return(invisible(obj))
}

These don't change (no hidden @external$h1.model):

checkStats(fit1)

These do get updated correctly:

checkStats(fit0)

@yrosseel yrosseel merged commit 65d1a5c into yrosseel:master Jun 20, 2024
5 checks passed
@yrosseel
Copy link
Owner

Thanks! Merged now.

@TDJorgensen
Copy link
Contributor Author

Thanks!
FYI, the changes I made do lead to a different test statistic returned by default for single- vs. multiple-model tests. In the absence of other arguments, the single-model test returns the second element, whatever that is, which will be Browne's (1984) when in @test, even if other scaled tests are in @test. In contrast, a multimodel test (in the absence of other arguments) will default to the first scaled @test element.

I'm not sure if you find that problematic, since most users will never call lavaan(test=) with a vector. If they do, they should be careful to know what they are doing.

Should I add a Note to the lavTestLRT.Rd file about this?
Or adjust the lav_test_lrt_single_model() checks to prefer scaled over Browne tests?

@yrosseel
Copy link
Owner

I will take a look at this soon (next week), when the semester is finally over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants