First steps with the Package jmleIRT
Jan Steinfeld & Alexander Robitzsch
September 05, 2025
Source:vignettes/jmleIRT-intro.Rmd
jmleIRT-intro.Rmd
Introduction
The jmleIRT
package provides an implementation of Joint
Maximum Likelihood Estimation (JMLE) for the Rasch (1PL) model. It
allows estimation of item difficulties and person abilities from
dichotomous response data with bias correction and weighted likelihood
estimation options.
Rasch Model Specification
For person and item , the Rasch model posits the probability of a correct response as:
where represents the ability of person and the difficulty of item .
Joint Maximum Likelihood Estimation
The joint likelihood across all persons and items is
JMLE alternates updates for and until convergence, providing simultaneous estimates of person and item parameters.
Bias Correction
Finite samples and extreme scores induce bias in JMLE estimates. The package implements:
- Epsilon bias stabilization: Adding a small to avoid infinite logits and improve numerical stability.
- Analytical bias correction: Drawing on methods from psychometric literature to reduce bias in item difficulty estimates.
Using the jmleIRT Package
Key features: - Missing values by design are allowed
(NA
). - Optional epsilon adjustment (eps
) to
reduce estimation bias from extreme scores. - Centering based on either
“items” or “persons” to ensure identifiability. - Post-hoc bias
correction (bias_correction = TRUE/FALSE
). - Optional
computation of Warm’s weighted likelihood estimates (WLE) for person
parameters (estimatewle = TRUE
). - Fast Newton-Raphson
optimization in C++.
Simulating Data
We first simulate a dataset of person responses.
N <- 100 # persons
I <- 10 # items
X <- matrix(rbinom(N * I, 1, 0.5), nrow = N)
# randomly set 10% of entries to missing
X[sample(length(X), size = 0.1 * length(X))] <- NA
head(X)
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#> [1,] 0 1 0 1 0 0 0 0 1 1
#> [2,] 1 1 1 0 1 0 1 1 0 0
#> [3,] 1 0 0 1 1 0 0 0 0 1
#> [4,] 0 0 0 1 0 1 1 1 1 1
#> [5,] NA 0 NA 0 0 0 NA 1 0 0
#> [6,] 0 1 1 0 0 1 1 0 0 0
Basic JML Estimation
Run the JML estimation with centering on “items” (default):
fit <- jmle_estimation(
X, max_iter = 500, conv = 1e-5,
center = "items", bias_correction = FALSE,
estimatewle = FALSE, verbose = FALSE
)
str(fit)
#> List of 7
#> $ theta : num [1:100] -0.466 0.364 -0.466 0.364 -1.86 ...
#> $ beta : num [1:10] 0.472 -0.494 -0.216 -0.269 0.124 ...
#> $ iterations : int 500
#> $ converged : logi FALSE
#> $ bias_correction: logi FALSE
#> $ center : chr "items"
#> $ wle_estimate : num [1:100] NA NA NA NA NA NA NA NA NA NA ...
#> - attr(*, "class")= chr [1:2] "jmleIRT" "list"
The output is a list with:
-
theta
: person ability estimates -
beta
: item difficulty estimates -
iterations
: number of NR iterations -
converged
: convergence flag -
bias_correction
: whether applied -
center
: ‘items’ or ‘persons’
-
wle_estimate
: person WLEs (if requested)
Bias Correction
Bias correction rescales item difficulty estimates.
fit_bc <- jmle_estimation(X, center = "items", bias_correction = TRUE)
summary(fit_bc$beta)
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> -0.444924 -0.230269 0.009095 0.000000 0.234489 0.424776
Compare to the uncorrected version:
summary(fit$beta)
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> -0.49436 -0.25585 0.01011 0.00000 0.26054 0.47197
Warm’s WLE Estimates
Warm’s weighted likelihood estimates can be obtained in addition to JML estimates.
fit_wle <- jmle_estimation(X, center = "items", estimatewle = TRUE)
head(fit_wle$wle_estimate)
#> [1] -0.3779268 0.3781344 -0.3779268 0.3781344 -1.4876481 -0.3779268
Handling Missing Data
The function handles missing responses (NA
) without
failure:
X_miss <- X
X_miss[1:5, 1:2] <- NA
fit_miss <- jmle_estimation(X_miss, center = "items")
length(fit_miss$theta)
#> [1] 100
length(fit_miss$beta)
#> [1] 10