Learn R Programming

tirt (version 0.2.0)

mixed_irt: Mixed Item Response Model Estimation (Dichotomous & Polytomous) with Prior Support

Description

Provides a estimation framework for a broad class of different item response theory models. This function can model different combinations of item categories. Now supports flexible prior distributions for Bayesian estimation (MAP estimation).

Usage

mixed_irt(data, model = "2PL", method = "EM", control = list())

Value

A list containing:

  • item_params: Data frame of item parameters (discrimination, difficulty/thresholds, guessing).

  • person_params: A data frame of estimated person abilities (theta) and standard errors.

  • model_fit: A data frame containing fit statistics such as Akaike’s Information Criterion (AIC) and the Bayesian Information Criterion (BIC).

  • settings: A list of control parameters used in the estimation.

Arguments

data

A N x J data.frame. Binary items must be 0/1. Polytomous items should be continuous integers (0, 1, 2...).

model

A character vector of length J (one model per item). Supported: "Rasch", "2PL" (2-Parameter Logistic), "3PL" (3-Parameter Logistic), "GRM" (Graded Response Model), "GPCM" (Generalized Partial Credit Model), "PCM" (Partial Credit Model). If a single string is provided, it is applied to all the same type of items.

method

String. "EM" (Marginal Maximum Likelihood via Expectation-Maximization) or "MLE" (Joint Maximum Likelihood).

control

A list of control parameters for the estimation algorithm:

  • max_iter: Maximum number of EM iterations (default = 100).

  • converge_tol: Convergence criterion for parameter change (default = 1e-4).

  • theta_range: Numeric vector of length 2 specifying the integration grid bounds (default = c(-4, 4)).

  • quad_points: Number of quadrature points (default = 21).

  • verbose: Logical; if TRUE, prints progress to console.

  • prior: A list of model-specific prior distributions. Default is NULL (no priors). Format: list("2PL" = list(a = function(x) ..., b = function(x) ...), "GRM" = list(...)) Each model gets its own prior specification. All items of the same model share the same prior. Example: prior = list( "2PL" = list(a = function(x) dlnorm(x, 0, 0.5, log=TRUE), b = function(x) dnorm(x, 0, 2, log=TRUE)), "GRM" = list(a = function(x) dlnorm(x, 0, 0.5, log=TRUE), d = function(x) dnorm(x, 0, 2, log=TRUE)) )

Examples

Run this code
  # --- Example 1: Simulation (Mixed 2PL + GPCM) ---
  set.seed(2025)
  N <- 500
  n_bin <- 5
  n_poly <- 2
  J <- n_bin + n_poly

  # 1. Generate Theta (Wide range to match user request)
  true_theta <- rnorm(N, mean = 0, sd = 3)

  # 2. Simulation Helper: GPCM
  sim_gpcm <- function(theta, a, steps) {
    n_cat <- length(steps) + 1
    probs <- matrix(0, length(theta), n_cat)
    for(k in 1:n_cat) {
      score <- k - 1
      if(score == 0) numer <- rep(0, length(theta))
      else numer <- a * (score * theta - sum(steps[1:score]))
      probs[, k] <- exp(numer)
    }
    probs <- probs / rowSums(probs)
    apply(probs, 1, function(p) sample(0:(n_cat-1), 1, prob=p))
  }

  # 3. Create Data
  data_sim <- data.frame(matrix(NA, nrow = N, ncol = J))
  colnames(data_sim) <- paste0("Item_", 1:J)

  # Binary Items (2PL)
  a_bin <- runif(n_bin, 0.8, 1.5)
  b_bin <- seq(-3, 3, length.out = n_bin)
  for(j in 1:n_bin) {
    prob <- 1 / (1 + exp(-(a_bin[j] * (true_theta - b_bin[j]))))
    data_sim[, j] <- rbinom(N, 1, prob)
  }

  # Polytomous Items (GPCM)
  # Item 6: 2 steps (-2, 2)
  data_sim[, 6] <- sim_gpcm(true_theta, a=1.0, steps=c(-2, 2))
  # Item 7: 5 steps
  data_sim[, 7] <- sim_gpcm(true_theta, a=1.2, steps=c(-5, -2.5, 0, 2.5, 5))

  # 4. Run Estimation without prior
  # Note: Wide theta_range needed due to SD=3 in simulation
  my_models <- c(rep("2PL", n_bin), rep("GPCM", n_poly))

  res <- mixed_irt(data = data_sim, model = my_models, method = "EM",
                   control = list(max_iter = 20, theta_range = c(-6, 6)))

  head(res$item_params)
  print(res$model_fit)

  # \donttest{
  # 5. Run Estimation with prior (MAP)
  res_prior <- mixed_irt(data = data_sim, model = my_models, method = "EM",
                         control = list(max_iter = 20, theta_range = c(-6, 6),
                                       prior = list(
                                         "2PL" = list(
                                           a = function(x) dlnorm(x, 0, 0.5, log=TRUE),
                                           b = function(x) dnorm(x, 0, 2, log=TRUE)
                                         ),
                                         "GPCM" = list(
                                           a = function(x) dlnorm(x, 0, 0.5, log=TRUE),
                                           d = function(x) dnorm(x, 0, 2, log=TRUE)
                                         )
                                       )))
  head(res_prior$item_params)
  print(res_prior$model_fit)
  # --- Example 2: With Package Data ---
  data("ela2", package = "tirt")

  # Define Models (7 Binary, 3 Poly)
  real_models <- c(rep("2PL", 7), rep("GRM", 3))

  # Run Estimation
  real_res <- mixed_irt(ela2, model = real_models, method = "EM",
                        control = list(max_iter = 10))

  head(real_res$item_params)
  print(real_res$model_fit)
  # }

Run the code above in your browser using DataLab