--- title: "Psychometric Tools in tirt: Information, Scoring, Fit, DIF, and Mixtures" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Psychometric Tools in tirt: Information, Scoring, Fit, DIF, and Mixtures} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` **1. Overview** Once item and person parameters have been estimated, a psychometric study usually continues with a battery of follow-up analyses: evaluating measurement precision, building score-conversion tables, checking person and item fit, screening for local dependence and differential item functioning, summarizing reliability, and sometimes probing for latent subpopulations. This vignette walks through the post-estimation tools in **tirt**. Every function accepts the item-parameter data frame produced by `binary_irt()`, `polytomous_irt()`, or `mixed_irt()`, so the workflow is uniform across models. ```{r setup} library(tirt) ``` We start from a small simulated 2PL data set and a quick calibration. ```{r calibrate} set.seed(2025) sim <- sim_irt( n_people = 600, item_structure = list(list(model = "2PL", n_items = 12)) ) fit <- binary_irt(sim$resp, model = "2PL", method = "EM", control = list(max_iter = 20, verbose = FALSE)) head(fit$item_params) ``` **2. Item and Test Information** `item_info()` returns the Fisher information of each item across a grid of ability values, and `test_info()` sums it into the test information function together with the conditional standard error of measurement (SEM). ```{r information} theta_grid <- seq(-3, 3, by = 0.5) # Item information (items in rows, theta in columns) info <- item_info(fit$item_params, theta = theta_grid) round(info[1:3, ], 3) # Test information function and conditional SEM tif <- test_info(fit$item_params, theta = theta_grid) tif # Where does the test measure most precisely? tif$theta[which.max(tif$test_info)] ``` **3. Summed-Score to Theta Conversion Table** Operational programs report scale scores from raw (summed) scores. `score_table()` produces the conversion using the Lord-Wingersky recursion, supporting expected a posteriori (`"EAP"`), weighted likelihood (`"WLE"`), and maximum likelihood (`"MLE"`) scoring. ```{r score_table} # EAP conversion table (0 to 12 correct) score_table(fit$item_params, method = "EAP") # Maximum-likelihood conversion score_table(fit$item_params, method = "MLE") ``` **4. Person Fit** `person_fit()` computes the `lz` standardized log-likelihood index to identify examinees whose response patterns are unlikely under the model. ```{r person_fit} pf <- person_fit(sim$resp, fit$item_params, fit$person_params) head(pf) # Number of examinees flagged as potentially misfitting sum(pf$flag, na.rm = TRUE) ``` **5. Item Fit** `item_fit()` returns the infit and outfit mean-square statistics and their standardized versions, for dichotomous and polytomous items alike. ```{r item_fit} item_fit(sim$resp, fit$item_params) ``` **6. Local Dependence (Yen's Q3)** `ld_stats()` computes Yen's Q3 residual correlations for every item pair. Large positive values signal that a pair depends on something beyond the common trait, which is the situation a testlet model is designed to absorb. ```{r ld_stats} q3 <- ld_stats(sim$resp, fit$item_params) round(q3[1:5, 1:5], 3) # Largest absolute residual correlation attr(q3, "max_abs_q3") ``` **7. Differential Item Functioning** `dif()` screens dichotomous items for DIF using the Mantel-Haenszel procedure (with the ETS delta effect size and A/B/C flags) and logistic regression (which separates uniform and non-uniform DIF). Here we plant DIF in item 3. ```{r dif} resp_dif <- sim$resp grp <- rep(c("Reference", "Focal"), each = 300) flip <- grp == "Focal" & resp_dif[[3]] == 1 resp_dif[[3]][flip] <- rbinom(sum(flip), 1, 0.55) dif(resp_dif, group = grp)[, c("item", "MH_delta", "ETS_class", "LR_p")] ``` **8. Reliability** `reliability()` reports the empirical (marginal) reliability from person estimates and their standard errors, the model-based marginal reliability from the test information function, and classical Cronbach's alpha from the raw responses. ```{r reliability} reliability(person_params = fit$person_params, data = sim$resp, item_params = fit$item_params) ``` **9. Test Characteristic Curve** `tcc()` returns the expected score of each item and the test characteristic curve, which maps ability onto the number-correct metric. ```{r tcc} curves <- tcc(fit$item_params, theta = seq(-3, 3, by = 1)) curves$test_curve ``` **10. Multidimensional and Mixed Simulation** Two new simulators extend the data-generation toolkit. `sim_mirt()` produces compensatory multidimensional data (aligned with `mirt_binary()`), and `sim_tirt()` produces forms that mix independent items with testlets (aligned with `irt_trt()`). ```{r sim_mirt} # Two correlated dimensions, simple structure mdat <- sim_mirt( n_people = 400, dimension = 2, Sigma = matrix(c(1, 0.4, 0.4, 1), 2, 2), item_structure = list( list(model = "M2PL", n_items = 6, dims = 1), list(model = "M2PL", n_items = 6, dims = 2) ) ) head(mdat$true_params) ``` ```{r sim_tirt} # Independent items plus two testlets tdat <- sim_tirt( n_people = 400, item_structure = list( list(model = "2PL", n_items = 6), list(model = "2PLT", n_items = 4, testlet_id = "P1", testlet_var = 0.6), list(model = "GPCT", n_items = 3, categories = 3, testlet_id = "P2") ) ) tdat$true_item_params[, c("item_id", "model", "testlet")] ``` **11. Mixture (Latent-Class) IRT** `mixture_irt()` fits a mixture Rasch or 2PL model, in which the population is a blend of latent classes with class-specific item parameters. ```{r mixture} set.seed(11) N <- 300; J <- 8 b1 <- seq(-1.5, 1.5, length.out = J); b2 <- rev(b1) theta <- rnorm(N); cls <- rep(1:2, each = N / 2) rmat <- matrix(0, N, J) for (i in 1:N) { b <- if (cls[i] == 1) b1 else b2 rmat[i, ] <- rbinom(J, 1, 1 / (1 + exp(-(theta[i] - b)))) } mdf <- as.data.frame(rmat); names(mdf) <- paste0("I", 1:J) mix <- mixture_irt(mdf, n_class = 2, model = "Rasch", control = list(max_iter = 40, verbose = FALSE)) mix$class_params mix$model_fit ``` **12. Final Comment** Together with the estimation, calibration, and equating functions described in the companion vignette, these tools cover the routine post-estimation workflow of an operational testing program. For details on any function, use the help system, for example `?score_table`.