Skip to content

Commit

Permalink
Merge pull request #5 from brianmsm/compare-model-fit-initial
Browse files Browse the repository at this point in the history
compare-model-fit-initial
  • Loading branch information
brianmsm authored Aug 17, 2024
2 parents 9d88785 + 9c4139a commit c9e27ae
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 3 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: psymetrics
Type: Package
Title: Tools for Psychometric Analysis
Version: 0.1.1
Version: 0.1.2
Authors@R:
person(
given = "Brian",
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Generated by roxygen2: do not edit by hand

S3method(model_fit,lavaan)
S3method(print,compare_model_fit)
S3method(print,model_fit)
export(compare_model_fit)
export(model_fit)
23 changes: 23 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
# psymetrics 0.1.2

## New Features

### `compare_model_fit()` Function
- **Added:** New function `compare_model_fit()` allows for comparing fit indices across multiple `lavaan` model objects.
- **Usage:** You can pass multiple fitted `lavaan` model objects to `compare_model_fit()` and it will return a data frame with fit indices for each model, enabling easy comparison.
- **Verbose Option:** Added a `verbose` argument to control the display of informational messages during comparison.
- **Print Method:** Implemented a `print.compare_model_fit` method to provide a formatted output for easy reading of model comparisons.

### Enhanced `model_fit()` Function
- **Updated:** Improved the `model_fit()` function to handle multiple types of fit indices, including "standard", "scaled", and "robust".
- **Custom Metrics:** Introduced the `metrics` argument, allowing users to specify exactly which fit indices they want to extract. If `metrics` is set to "essential", a predefined set of common indices is returned.
- **Verbose Option:** Added a `verbose` argument to control the display of informational messages when metrics are adjusted according to the estimator type.
- **Print Method:** Implemented a `print.model_fit` method to provide a clean and formatted output for the fit indices, with customizable precision.


### Documentation
- **Updated:** Improved the documentation for `model_fit()` and added comprehensive examples showcasing how to use `compare_model_fit()`.

## Note
- **Tests Pending:** Unit tests for `model_fit()` and `compare_model_fit()` will be added in the next update to ensure consistent functionality and output formatting.

# psymetrics 0.1.1

## New Features
Expand Down
51 changes: 51 additions & 0 deletions R/compare_model_fit.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#' Compare Model Fit Indices Across Multiple Models
#'
#' @description `compare_model_fit()` compares the fit indices of two or more
#' models. It extracts the fit indices using `model_fit` and combines them into
#' a single data frame for easy comparison.
#'
#' @param ... Two or more model objects to be compared.
#' @param type A character string specifying the type of fit indices to extract.
#' Options are `"standard"`, `"scaled"`, and `"robust"`. Defaults to `NULL`,
#' which automatically selects `"scaled"` if a robust estimator is used, otherwise `"standard"`.
#' @param metrics A character vector specifying which fit indices to extract.
#' Defaults to `"essential"`, or a custom vector of indices.
#' @param verbose Logical. If `TRUE`, prints messages about the indices being adjusted.
#' @return A data frame containing the fit indices for each model, with an additional column identifying the models.
#' @export
#' @examples
#' library(lavaan)
#' model1 <- 'visual =~ x1 + x2 + x3'
#' model2 <- 'visual =~ x1 + x2 + x3 + x4'
#' fit1 <- cfa(model1, data = HolzingerSwineford1939, estimator = "MLR")
#' fit2 <- cfa(model2, data = HolzingerSwineford1939, estimator = "MLR")
#' compare_model_fit(fit1, fit2)

compare_model_fit <- function(..., type = NULL, metrics = "essential", verbose = TRUE) {
# Capture all the fit objects as a list
fits <- list(...)

# Ensure at least two models are provided for comparison
if (length(fits) < 2) {
cli::cli_alert_danger("At least two model fits must be provided for comparison.")
stop("At least two model fits must be provided for comparison.")
}

# Apply model_fit to each model in the list
fit_measures <- lapply(fits, model_fit, type = type, metrics = metrics, verbose = verbose)

# Combine the dataframes vertically
combined_measures <- do.call(rbind, fit_measures)

# Add a column to identify each model
model_names <- sapply(substitute(list(...))[-1L], deparse)
combined_measures$model <- rep(model_names, times = sapply(fit_measures, nrow))

# Reorder columns so that "model" is the first column
combined_measures <- combined_measures[, c("model", setdiff(names(combined_measures), "model"))]

# Assign the custom class for print method
class(combined_measures) <- c("compare_model_fit", class(combined_measures))

return(combined_measures)
}
46 changes: 46 additions & 0 deletions R/print.compare_model_fit.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#' Print Method for compare_model_fit Objects
#'
#' @description This function provides a custom print method for objects of class
#' `compare_model_fit`, which are generated by the `compare_model_fit()` function.
#' It formats and displays the comparison of model fit indices in a clear and
#' readable table.
#'
#' @param x An object of class `compare_model_fit`, created by the `compare_model_fit()` function.
#' @param digits Integer. Number of digits to use for displaying numeric values. Defaults to 3.
#' @param p_digits Integer. Number of digits to use for displaying p-values. Defaults to 3.
#' @param format Character. The format in which to print the table. Options are `"text"`, `"markdown"`, or `"html"`. Defaults to `"text"`.
#' @param ... Additional arguments passed to `insight::export_table()`.
#'
#' @return Invisibly returns the `compare_model_fit` object. The main purpose of this function is to print the formatted comparison table.
#' @export
#'
#' @examples
#' library(psymetrics)
#' library(lavaan)
#'
#' model1 <- 'visual =~ x1 + x2 + x3'
#' model2 <- 'visual =~ x1 + x2 + x3 + x4'
#' fit1 <- cfa(model1, data = HolzingerSwineford1939, estimator = "MLR")
#' fit2 <- cfa(model2, data = HolzingerSwineford1939, estimator = "MLR")
#' comparison <- compare_model_fit(fit1, fit2)
#' print(comparison, digits = 2)


print.compare_model_fit <- function(x, digits = 3, p_digits = 3, format = "text", ...) {
# Format the comparison table
formatted_table <- insight::format_table(x, digits = digits, p_digits = p_digits)

# Print the formatted table
cat(
insight::export_table(
x = formatted_table,
digits = digits,
format = format,
caption = c("# Model Fit Comparison:", "blue"),
...
)
)

# Return the object invisibly
invisible(x)
}
14 changes: 13 additions & 1 deletion README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ You can install the development version of psymetrics from [GitHub](https://gith
pak::pak("brianmsm/psymetrics")
```

## Example
## Getting Fit Indices

Here is an example of how to use the psymetrics package with a model created using lavaan.

Expand All @@ -56,3 +56,15 @@ model_fit(fit, metrics = c("cfi", "tli"))
```

This example demonstrates how to extract and print various fit indices from a confirmatory factor analysis (CFA) model using psymetrics. You can choose between standard, scaled, or robust fit indices, and even specify custom sets of indices to extract.

## Comparing Fit Indices

```{r}
fit_1 <- cfa(model, data = HolzingerSwineford1939, estimator = "MLR")
fit_2 <- cfa(model, data = HolzingerSwineford1939, estimator = "ULSM")
compare_model_fit(fit_1, fit_2)
```

In this example, compare_model_fit is used to compare the fit indices of two different models. This function allows you to easily see the differences in model fit across different estimation methods or model specifications.

22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ You can install the development version of psymetrics from
pak::pak("brianmsm/psymetrics")
```

## Example
## Getting Fit Indices

Here is an example of how to use the psymetrics package with a model
created using lavaan.
Expand Down Expand Up @@ -65,3 +65,23 @@ This example demonstrates how to extract and print various fit indices
from a confirmatory factor analysis (CFA) model using psymetrics. You
can choose between standard, scaled, or robust fit indices, and even
specify custom sets of indices to extract.

## Comparing Fit Indices

``` r
fit_1 <- cfa(model, data = HolzingerSwineford1939, estimator = "MLR")
fit_2 <- cfa(model, data = HolzingerSwineford1939, estimator = "ULSM")

compare_model_fit(fit_1, fit_2)
#> # Model Fit Comparison:
#>
#> model | NOBS | ESTIMATOR | NPAR | Chi2(24) | p (Chi2) | CFI | TLI | RMSEA | RMSEA CI | SRMR
#> ---------------------------------------------------------------------------------------------------------
#> fit_1 | 301.000 | MLR | 21.000 | 87.132 | < .001 | 0.925 | 0.888 | 0.093 | [0.07, 0.12] | 0.065
#> fit_2 | 301.000 | ULSM | 21.000 | 90.600 | < .001 | 0.931 | 0.897 | 0.096 | [0.07, 0.12] | 0.059
```

In this example, compare_model_fit is used to compare the fit indices of
two different models. This function allows you to easily see the
differences in model fit across different estimation methods or model
specifications.
36 changes: 36 additions & 0 deletions man/compare_model_fit.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions man/print.compare_model_fit.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c9e27ae

Please sign in to comment.