diff --git a/DESCRIPTION b/DESCRIPTION index 1a67e08..88f2b3d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: lavaanExtra Title: Convenience Functions for Package 'lavaan' -Version: 0.2.1 +Version: 0.2.1.1 Date: 2024-07-01 Authors@R: person("Rémi", "Thériault", , "remi.theriault@mail.mcgill.ca", role = c("aut", "cre"), @@ -40,6 +40,6 @@ Suggests: Config/testthat/edition: 3 Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 VignetteBuilder: knitr Language: en-US diff --git a/NEWS.md b/NEWS.md index 6fc6df2..ac9207c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,8 @@ # lavaanExtra 0.2.2 * Incoming ✨ -# lavaanExtra 0.2.1.1 -* Incoming ✨ +## lavaanExtra 0.2.1.1 +* `nice_fit()`: add `cutoffs` argument to control display of fit index cutoffs, addressing JOSS review feedback (#21) # lavaanExtra 0.2.1 * New CRAN submission diff --git a/R/nice_fit.R b/R/nice_fit.R index ca6d1b8..c361a80 100644 --- a/R/nice_fit.R +++ b/R/nice_fit.R @@ -9,14 +9,14 @@ #' biased (\doi{10.1007/s11336-016-9552-7}) in a noticeable #' way for smaller samples (thanks to James Uanhoro for this change). #' -#' If using `guidelines = TRUE`, please carefully consider the following 2023 +#' If using `guidelines = TRUE` or `cutoffs = TRUE`, please carefully consider the following 2023 #' quote from Terrence D. Jorgensen: #' #' _I do not recommend including cutoffs in the table, as doing so would #' perpetuate their misuse. Fit indices are not test statistics, and their #' suggested cutoffs are not critical values associated with known Type I #' error rates. Numerous simulation studies have shown how poorly cutoffs -#' perform in model selection (e.g., , Jorgensen et al. (2018). Instead of +#' perform in model selection (e.g., Jorgensen et al., 2018). Instead of #' test statistics, fit indices were designed to be measures of effect size #' (practical significance), which complement the chi-squared test of #' statistical significance. The range of RMSEA interpretations above is more @@ -34,6 +34,10 @@ #' @param guidelines Logical, if `nice_table = TRUE`, whether to display #' include reference values based on Schreiber (2017), Table 3, at the #' bottom of the table. +#' @param cutoffs Logical, if `nice_table = TRUE`, whether to display +#' suggested fit index cutoffs at the bottom of the table. Defaults to +#' same value as `guidelines`. Setting this to `FALSE` provides a way to +#' hide cutoffs while keeping other guideline information. #' @param stars Logical, if `nice_table = TRUE`, whether to display #' significance stars (defaults to `FALSE`). #' @param verbose Logical, whether to display messages and warnings. @@ -44,6 +48,10 @@ #' @references Schreiber, J. B. (2017). Update to core reporting practices in #' structural equation modeling. *Research in social and administrative pharmacy*, #' *13*(3), 634-643. \doi{10.1016/j.sapharm.2016.06.006} +#' +#' Jorgensen, T. D., Pornprasertmanit, S., Schoemann, A. M., & Rosseel, Y. (2018). +#' Useful tools for structural equation modeling. *Structural Equation Modeling*, +#' *25*(1), 1-27. \doi{10.1037/met0000152} #' @examplesIf requireNamespace("lavaan", quietly = TRUE) #' x <- paste0("x", 1:9) #' (latent <- list( @@ -68,6 +76,7 @@ nice_fit <- function(model, model.labels, nice_table = FALSE, guidelines = TRUE, + cutoffs = guidelines, stars = FALSE, verbose = TRUE) { if (inherits(model, "list") && all(unlist(lapply(model, inherits, "lavaan")))) { @@ -122,9 +131,9 @@ nice_fit <- function(model, table <- rempsyc::nice_table(x, stars = stars) table <- flextable::align(table, align = "center", part = "all") - if (isTRUE(guidelines)) { + if (isTRUE(cutoffs)) { values_to_add <- c( - Model = "Common guidelines", + Model = "Suggested cutoffs", chi2 = "\u2014", df = "\u2014", chi2.df = "< 2 or 3", diff --git a/man/nice_fit.Rd b/man/nice_fit.Rd index 898af99..3b2fee0 100644 --- a/man/nice_fit.Rd +++ b/man/nice_fit.Rd @@ -9,6 +9,7 @@ nice_fit( model.labels, nice_table = FALSE, guidelines = TRUE, + cutoffs = guidelines, stars = FALSE, verbose = TRUE ) @@ -27,6 +28,11 @@ is unnamed, defaults to generic numbering.} include reference values based on Schreiber (2017), Table 3, at the bottom of the table.} +\item{cutoffs}{Logical, if \code{nice_table = TRUE}, whether to display +suggested fit index cutoffs at the bottom of the table. Defaults to +same value as \code{guidelines}. Setting this to \code{FALSE} provides a way to +hide cutoffs while keeping other guideline information.} + \item{stars}{Logical, if \code{nice_table = TRUE}, whether to display significance stars (defaults to \code{FALSE}).} @@ -48,14 +54,14 @@ Note that \code{nice_fit} reports the unbiased SRMR through biased (\doi{10.1007/s11336-016-9552-7}) in a noticeable way for smaller samples (thanks to James Uanhoro for this change). -If using \code{guidelines = TRUE}, please carefully consider the following 2023 +If using \code{guidelines = TRUE} or \code{cutoffs = TRUE}, please carefully consider the following 2023 quote from Terrence D. Jorgensen: \emph{I do not recommend including cutoffs in the table, as doing so would perpetuate their misuse. Fit indices are not test statistics, and their suggested cutoffs are not critical values associated with known Type I error rates. Numerous simulation studies have shown how poorly cutoffs -perform in model selection (e.g., , Jorgensen et al. (2018). Instead of +perform in model selection (e.g., Jorgensen et al., 2018). Instead of test statistics, fit indices were designed to be measures of effect size (practical significance), which complement the chi-squared test of statistical significance. The range of RMSEA interpretations above is more @@ -90,4 +96,8 @@ nice_fit(fit) Schreiber, J. B. (2017). Update to core reporting practices in structural equation modeling. \emph{Research in social and administrative pharmacy}, \emph{13}(3), 634-643. \doi{10.1016/j.sapharm.2016.06.006} + +Jorgensen, T. D., Pornprasertmanit, S., Schoemann, A. M., & Rosseel, Y. (2018). +Useful tools for structural equation modeling. \emph{Structural Equation Modeling}, +\emph{25}(1), 1-27. \doi{10.1037/met0000152} } diff --git a/tests/testthat/test-nice_fit.R b/tests/testthat/test-nice_fit.R index a918371..cb91163 100644 --- a/tests/testthat/test-nice_fit.R +++ b/tests/testthat/test-nice_fit.R @@ -93,4 +93,34 @@ test_that("nice_fit test categorical variable", { ) }) +test_that("nice_fit cutoffs parameter works", { + skip_if_not_installed("rempsyc") + + # Test with cutoffs = TRUE (should have footer content) + result_with_cutoffs <- nice_fit(fit, nice_table = TRUE, cutoffs = TRUE, verbose = FALSE) + expect_s3_class(result_with_cutoffs, "flextable") + expect_gt(length(result_with_cutoffs$footer$content$data), 0) + + # Test with cutoffs = FALSE (should have no footer content) + result_without_cutoffs <- nice_fit(fit, nice_table = TRUE, cutoffs = FALSE, verbose = FALSE) + expect_s3_class(result_without_cutoffs, "flextable") + expect_equal(length(result_without_cutoffs$footer$content$data), 0) +}) + +test_that("nice_fit cutoffs parameter defaults to guidelines value", { + skip_if_not_installed("rempsyc") + + # Test that cutoffs defaults to guidelines value + result_guidelines_true <- nice_fit(fit, nice_table = TRUE, guidelines = TRUE, verbose = FALSE) + result_cutoffs_true <- nice_fit(fit, nice_table = TRUE, cutoffs = TRUE, verbose = FALSE) + + # Both should have footer content when cutoffs/guidelines are TRUE + expect_gt(length(result_guidelines_true$footer$content$data), 0) + expect_gt(length(result_cutoffs_true$footer$content$data), 0) + + # Test that cutoffs can override guidelines + result_mixed <- nice_fit(fit, nice_table = TRUE, guidelines = TRUE, cutoffs = FALSE, verbose = FALSE) + expect_equal(length(result_mixed$footer$content$data), 0) +}) +