Alignment Optimization with mirt

Item response theory
Data harmonization

A note on alignment optimization with mirt output, and obtaining factor scores

Author

Mark Lai

Published

August 27, 2024

library(sirt)
- sirt 4.0-32 (2024-01-17 23:27:50)
library(mirt)
Loading required package: stats4
Loading required package: lattice
# Example from `mirt::multipleGroup()`
# single factor
set.seed(12345)
a <- matrix(abs(rnorm(15, 1, .3)), ncol = 1)
d <- matrix(rnorm(15, 0, .7), ncol = 1)
itemtype <- rep("2PL", nrow(a))
N <- 1000
dataset1 <- simdata(a, d, N, itemtype)
dataset2 <- simdata(a, d, N, itemtype, mu = .1, sigma = matrix(1.5))
dat <- rbind(dataset1, dataset2)
group <- c(rep("D1", N), rep("D2", N))
# completely separate analyses
mod_configural <- multipleGroup(dat, 1, group = group)

Iteration: 1, Log-Lik: -18088.494, Max-Change: 0.37763
Iteration: 2, Log-Lik: -17943.205, Max-Change: 0.18868
Iteration: 3, Log-Lik: -17915.337, Max-Change: 0.10010
Iteration: 4, Log-Lik: -17907.752, Max-Change: 0.05644
Iteration: 5, Log-Lik: -17905.241, Max-Change: 0.03385
Iteration: 6, Log-Lik: -17904.329, Max-Change: 0.02073
Iteration: 7, Log-Lik: -17903.856, Max-Change: 0.00942
Iteration: 8, Log-Lik: -17903.798, Max-Change: 0.00531
Iteration: 9, Log-Lik: -17903.778, Max-Change: 0.00309
Iteration: 10, Log-Lik: -17903.767, Max-Change: 0.00141
Iteration: 11, Log-Lik: -17903.764, Max-Change: 0.00087
Iteration: 12, Log-Lik: -17903.764, Max-Change: 0.00041
Iteration: 13, Log-Lik: -17903.763, Max-Change: 0.00036
Iteration: 14, Log-Lik: -17903.763, Max-Change: 0.00018
Iteration: 15, Log-Lik: -17903.763, Max-Change: 0.00013
Iteration: 16, Log-Lik: -17903.763, Max-Change: 0.00009
coef1 <- mirt.wrapper.coef(mod_configural)
lambda <- matrix(coef1$coef[, "a1"], nrow = 2)
tau <- matrix(coef1$coef[, "d"], nrow = 2)
aligned <- invariance.alignment(lambda, tau)
# Aligned latent means and SDs
aligned$pars
       alpha0     psi0
G1 0.00000000 1.000000
G2 0.07777356 1.228109

Factor Scoring by refitting the model using the aligned parameters

# Constrain latent means and variances to the aligned level
mod2 <- mirt.model("
F1 = 1-15
START [D2] = (GROUP, MEAN_1, 0.07777356), (GROUP, COV_11, 1.508252)
")
mod_aligned <- multipleGroup(dat, model = mod2, group = group)

Iteration: 1, Log-Lik: -18035.495, Max-Change: 0.37857
Iteration: 2, Log-Lik: -17924.594, Max-Change: 0.15583
Iteration: 3, Log-Lik: -17908.869, Max-Change: 0.07828
Iteration: 4, Log-Lik: -17905.533, Max-Change: 0.03693
Iteration: 5, Log-Lik: -17904.461, Max-Change: 0.01973
Iteration: 6, Log-Lik: -17904.062, Max-Change: 0.01080
Iteration: 7, Log-Lik: -17903.840, Max-Change: 0.00406
Iteration: 8, Log-Lik: -17903.806, Max-Change: 0.00281
Iteration: 9, Log-Lik: -17903.787, Max-Change: 0.00190
Iteration: 10, Log-Lik: -17903.779, Max-Change: 0.00152
Iteration: 11, Log-Lik: -17903.773, Max-Change: 0.00201
Iteration: 12, Log-Lik: -17903.769, Max-Change: 0.00137
Iteration: 13, Log-Lik: -17903.764, Max-Change: 0.00081
Iteration: 14, Log-Lik: -17903.764, Max-Change: 0.00060
Iteration: 15, Log-Lik: -17903.763, Max-Change: 0.00065
Iteration: 16, Log-Lik: -17903.763, Max-Change: 0.00033
Iteration: 17, Log-Lik: -17903.763, Max-Change: 0.00040
Iteration: 18, Log-Lik: -17903.763, Max-Change: 0.00035
Iteration: 19, Log-Lik: -17903.763, Max-Change: 0.00022
Iteration: 20, Log-Lik: -17903.763, Max-Change: 0.00018
Iteration: 21, Log-Lik: -17903.763, Max-Change: 0.00022
Iteration: 22, Log-Lik: -17903.763, Max-Change: 0.00009
# Factor scores
fs <- fscores(mod_aligned,
    mean = c(0, 0),
    cov = c(1, 1),
    full.scores.SE = TRUE
)
head(fs)
         F1     SE_F1
1 0.3247557 0.4820845
2 1.1655768 0.5410867
3 0.7410628 0.5048955
4 1.0643392 0.5314329
5 1.0623173 0.5312461
6 0.9071798 0.5176646