| run_mst | R Documentation |
Simulates an MST administration for a panel of examinees. At each stage,
examinees are routed to a module based on their current ability estimate
(or a set of cut scores), and a final ability estimate is computed from the
accumulated responses across all administered stages. The function supports
all IRT models available in irtQ (1PLM, 2PLM, 3PLM, GRM, GPCM) and
all scoring methods available in est_score.
The overall structure - separate route_score and final_score
list arguments, and the route_map/module matrix conventions -
was inspired by the randomMST() function in the mstR package
(Magis et al., 2017).
run_mst(
x,
route_map,
module,
theta = NULL,
response = NULL,
D = 1,
ini_mod = NULL,
route_method = "bmat",
cut_score = NULL,
route_score = list(method = "ML", range = c(-5, 5), norm.prior = c(0, 1), nquad = 41L,
tol = 1e-04, max.iter = 100L, fence.a = 3, fence.b = NULL, intpol = TRUE, range.tcc =
c(-7, 7), max.it = 500L),
final_score = list(method = "ML", range = c(-5, 5), norm.prior = c(0, 1), nquad = 41L,
tol = 1e-04, max.iter = 100L, fence.a = 3, fence.b = NULL, intpol = TRUE, range.tcc =
c(-7, 7), max.it = 500L),
se = TRUE,
missing = NA,
verbose = TRUE,
return_full_resp = FALSE
)
x |
A data frame of item bank metadata following the irtQ format
(columns: |
route_map |
A binary square matrix defining the MST transition
structure. A 1 at row i, column j means that a test taker
can be routed from module i to module j. Equivalent to the
|
module |
A binary matrix mapping items (rows) to modules (columns).
|
theta |
A numeric vector of true ability values, one per examinee
(length N). Used to simulate item responses when |
response |
An optional N x J matrix of observed item
responses, where N is the number of examinees and J is the
total number of items in the item bank ( |
D |
A numeric scaling constant for the IRT model. Use |
ini_mod |
Either |
route_method |
A character string specifying the adaptive routing method used to select the next module at each stage transition.
Default is |
cut_score |
A list of numeric vectors specifying the routing cut scores
used when |
route_score |
A named list specifying the scoring method and options used to obtain intermediate ability estimates for routing decisions (applied after every stage except the last). Fields:
Unspecified fields take their defaults; the full default is
|
final_score |
A named list specifying the scoring method and options
for the final ability estimate (applied to all items accumulated across
the entire administered pathway). Supports all fields in
The full default is equivalent to
|
se |
Logical. Whether to compute and return the standard error of the
final ability estimate. SE is computed for all |
missing |
A scalar specifying how missing (not-administered) responses
are represented in |
verbose |
Logical. If |
return_full_resp |
Logical. If |
Panel structure: The function first calls panel_info
to identify stages, module membership, and valid pathways from
route_map. Module m's items are those where
module[, m] == 1.
Response simulation: If response is NULL, item
responses are simulated from theta using simdat.
Stage-1 module assignment: When ini_mod = NULL (default),
each examinee is independently assigned to a stage-1 module by uniform
random sampling from panel_info(route_map)$config[[1]]. For panels
with a single stage-1 module (the most common design), this is equivalent
to a fixed assignment. For panels with multiple stage-1 modules (e.g., a
2-3-3 or 3-2-3 design), random assignment approximates the spiralling or
booklet-based allocation used in operational testing. When ini_mod
is an integer, all examinees start at the specified stage-1 module.
Routing (stages 1 to n.stage - 1): After each non-final stage,
an intermediate ability estimate is obtained from the current stage's
responses using the route_score method. This estimate is used to
select the next-stage module:
"bmat": the reachable module (via route_map) whose
mean item location is closest to the routing estimate is selected.
For dichotomous items, the location is the b parameter; for
GRM/GPCM items, it is the mean of the threshold / step parameters.
"mfi": the reachable module with the highest test
information at the routing estimate is selected.
NULL: the routing estimate is compared against the cut
scores in cut_score[[s]] (for the transition from stage
s to stage s+1) to assign a rank, and the rank-th
reachable module (ordered by module index) is administered. If the
rank exceeds the number of reachable modules, the last module is used.
Final scoring: Responses from all administered stages are
concatenated, and the final ability estimate is computed using the
final_score method.
An object of class "run_mst", which is a named list
containing:
callThe matched function call.
est.thetaA numeric vector of length N containing the final ability estimate for each examinee.
se.thetaA numeric vector of length N containing
the standard error of the final ability estimate. All seven
final_score methods return SE; for "EAP.SUM" and
"INV.TCC", SE is the posterior standard deviation from the
pre-computed lookup table. NA when se = FALSE, when all
responses are missing, or when the sum score falls outside the
estimable range.
theta.routeAn N x n.stage numeric matrix
of ability estimates. Columns 1 to n.stage - 1 are the
intermediate routing estimates; column n.stage is the final
estimate (equal to est.theta).
pathAn N x n.stage integer matrix of
administered module indices.
true.thetaThe theta argument (true abilities), or
NULL if not provided.
panelThe output of panel_info(route_map).
DThe scaling constant used.
route.methodThe route_method argument.
route.scoreThe fully-merged route_score list
(with all defaults applied).
final.scoreThe fully-merged final_score list
(with all defaults applied).
NNumber of examinees.
full.respAlways present in the returned list. When
return_full_resp = TRUE, an N x J integer matrix
of all item responses, where N is the number of examinees and
J = nrow(x) (total items in the item bank). Row names are
"examinee.1", "examinee.2", etc.; column names are the
item IDs from x$id. NA for items not administered to a
given examinee. When return_full_resp = FALSE (default), this
element is NULL.
Bock, R. D., & Mislevy, R. J. (1982). Adaptive EAP estimation of ability in a microcomputer environment. Applied Psychological Measurement, 6(4), 431-444. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1177/014662168200600405")}
Han, K. T. (2016). Maximum likelihood score estimation method with fences for short-length tests and computerized adaptive tests. Applied Psychological Measurement, 40(4), 289-301. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1177/0146621616631317")}
Lim, H., Davey, T., & Wells, C. S. (2021). A recursion-based analytical approach to evaluate the performance of MST. Journal of Educational Measurement, 58(2), 154-178. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1111/jedm.12276")}
Magis, D., Yan, D., & von Davier, A. A. (2017). Computerized adaptive and multistage testing with R: Using packages catR and mstR. Springer. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1007/978-3-319-69218-0")}
Thissen, D., Pommerich, M., Billeaud, K., & Williams, V. S. L. (1995). Item response theory for scores on tests including polytomous items with ordered responses. Applied Psychological Measurement, 19(1), 39-49. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1177/014662169501900105")}
Warm, T. A. (1989). Weighted likelihood estimation of ability in item response theory. Psychometrika, 54(3), 427-450. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1007/BF02294627")}
panel_info, reval_mst,
est_score, simdat, simMST
## ---------------------------------------------------------
## Example 1: bmat routing with ML scoring (default)
## Using the simMST 1-3-3 panel (7 modules, 8 items each)
## ---------------------------------------------------------
# Load item bank metadata
x <- simMST$item_bank
module <- simMST$module
route_map <- simMST$route_map
# True abilities for 500 examinees
set.seed(42)
theta_true <- rnorm(500, mean = 0, sd = 1)
# Run MST simulation with bmat routing and ML scoring
result_bmat <- run_mst(
x = x,
route_map = route_map,
module = module,
theta = theta_true,
D = 1.702,
route_method = "bmat",
route_score = list(method = "ML", range = c(-4, 4)),
final_score = list(method = "ML", range = c(-4, 4)),
se = TRUE
)
# Print simulation summary
print(result_bmat)
# Final ability estimates
head(result_bmat$est.theta)
# Module pathway taken by each examinee
head(result_bmat$path)
## ---------------------------------------------------------
## Example 2: Cut-score routing with EAP routing and ML final scoring
## EAP keeps the routing estimate finite even from a short Stage 1
## module (e.g., a perfect or zero score), while ML avoids the shrinkage
## that EAP's prior would otherwise introduce in the reported final score.
## ---------------------------------------------------------
cut_score <- simMST$cut_score # list(c(-0.45, 0.46), c(-0.42, 0.45))
result_cut <- run_mst(
x = x,
route_map = route_map,
module = module,
theta = theta_true,
D = 1.702,
route_method = NULL,
cut_score = cut_score,
route_score = list(method = "EAP", norm.prior = c(0, 1), nquad = 41),
final_score = list(method = "ML", range = c(-4, 4)),
se = TRUE
)
print(result_cut)
## ---------------------------------------------------------
## Example 3: Using a pre-generated response matrix
## (useful when comparing multiple routing methods on the
## same simulated responses, or when using real observed data)
## ---------------------------------------------------------
# Generate responses once from theta using simdat()
set.seed(123)
theta_true2 <- rnorm(500, mean = 0, sd = 1)
resp_matrix <- simdat(x = x, theta = theta_true2, D = 1.702)
# resp_matrix is an N x J matrix (N examinees x J total items in bank)
# Now run run_mst() twice with the SAME responses but different routing methods
# Method A: bmat routing
result_A <- run_mst(
x = x,
route_map = route_map,
module = module,
theta = theta_true2, # kept for bias/RMSE evaluation
response = resp_matrix, # pre-generated N x J response matrix
D = 1.702,
route_method = "bmat",
route_score = list(method = "EAP", norm.prior = c(0, 1), nquad = 41),
final_score = list(method = "ML", range = c(-4, 4)),
se = FALSE
)
# Method B: cut-score routing using the same responses
result_B <- run_mst(
x = x,
route_map = route_map,
module = module,
theta = theta_true2,
response = resp_matrix, # identical response matrix -> fair comparison
D = 1.702,
route_method = NULL,
cut_score = simMST$cut_score,
route_score = list(method = "EAP", norm.prior = c(0, 1), nquad = 41),
final_score = list(method = "ML", range = c(-4, 4)),
se = FALSE
)
# Compare RMSE of the two routing strategies
rmse_A <- sqrt(mean((result_A$est.theta - theta_true2)^2))
rmse_B <- sqrt(mean((result_B$est.theta - theta_true2)^2))
cat(sprintf("RMSE (bmat): %.4f\n", rmse_A))
cat(sprintf("RMSE (cut-score): %.4f\n", rmse_B))
## ---------------------------------------------------------
## Example 4: TIF-based cut scores via find_cut()
## find_cut() computes principled cut scores from TIF crossings.
## This prevents anomalous routing under MFI-like heuristics.
## ---------------------------------------------------------
# Derive cut scores from TIF crossings between adjacent modules
cut_result <- find_cut(
x = x,
module = module,
route_map = route_map
)
# Inspect the derived cut scores
print(cut_result)
# Use the derived cut scores for routing (route_method = NULL)
result_findcut <- run_mst(
x = x,
route_map = route_map,
module = module,
theta = theta_true,
D = 1.702,
route_method = NULL,
cut_score = cut_result$cut_score,
route_score = list(method = "EAP", norm.prior = c(0, 1), nquad = 41),
final_score = list(method = "ML", range = c(-4, 4)),
se = TRUE
)
print(result_findcut)
## Visualise the TIF-based cut scores used for routing
plot(cut_result)
## ---------------------------------------------------------
## Example 5: INV.TCC routing and final scoring
## (pre-computed lookup tables; efficient for large N)
## ---------------------------------------------------------
# INV.TCC can be used as both the routing and final scoring method.
# Before the examinee loop, run_mst() pre-computes a sum_score -> theta
# lookup table for every module (routing) and for every unique complete
# pathway (final scoring), consistent with the reval_mst() approach.
# SE is now returned correctly for INV.TCC (posterior SD from the table).
result_inv <- run_mst(
x = x,
route_map = route_map,
module = module,
theta = theta_true,
D = 1.702,
route_method = "bmat",
route_score = list(method = "INV.TCC", range.tcc = c(-7, 7)),
final_score = list(method = "INV.TCC", range.tcc = c(-7, 7)),
se = TRUE
)
print(result_inv)
# SE is now populated (posterior SD from the pre-computed table)
head(result_inv$se.theta)
# Compare RMSE: INV.TCC routing vs. ML routing (result_bmat from Example 1)
rmse_inv <- sqrt(mean((result_inv$est.theta - theta_true)^2, na.rm = TRUE))
rmse_ml <- sqrt(mean((result_bmat$est.theta - theta_true)^2, na.rm = TRUE))
cat(sprintf("RMSE (INV.TCC routing + scoring): %.4f\n", rmse_inv))
cat(sprintf("RMSE (ML routing + scoring): %.4f\n", rmse_ml))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.