RMitemRestscoreCutoff: Simulation-Based Item-Restscore Null Distribution

View source: R/item_restscore_cutoff.R

RMitemRestscoreCutoffR Documentation

Simulation-Based Item-Restscore Null Distribution

Description

Uses parametric bootstrap simulation to build the null distribution of the item-restscore statistic for RMitemRestscore. This function simulates data from a correctly fitting Rasch model that mimics your data and returns, per item, the simulated difference between observed and expected item-restscore gamma.

Usage

RMitemRestscoreCutoff(
  data,
  iterations = 400,
  parallel = TRUE,
  n_cores = NULL,
  verbose = FALSE,
  seed = NULL,
  cutoff_method = "hdci",
  hdci_width = 0.95,
  dgp = c("conditional", "resample")
)

Arguments

data

A data.frame or matrix of item responses. Items must be scored starting at 0 (non-negative integers). Only complete cases (rows without any NA) are used.

iterations

Integer. Number of simulation iterations (default 400).

parallel

Logical. Use parallel processing via mirai if available (default TRUE).

n_cores

Integer or NULL. Number of parallel workers. When NULL, getOption("mc.cores") is checked first. If neither is set and parallel = TRUE, a warning is issued and execution falls back to sequential (single core) processing.

verbose

Logical. Show a progress bar (default FALSE).

seed

Integer or NULL. Random seed for reproducibility. See easyRasch2-reproducibility for what this guarantees and how it interacts with parallel.

cutoff_method

Character string specifying how the intervals are computed. Either "hdci" (default) for the Highest Density Interval via ggdist::hdci(), or "quantile" for the 2.5th/97.5th percentiles via stats::quantile().

hdci_width

Numeric. Width of the HDCI when cutoff_method = "hdci". Default is 0.95 (95% HDCI). Ignored when cutoff_method = "quantile".

The interval is a description of where a fitting item's difference is expected to fall, not a decision rule. Flagging every item outside a width-w interval tests all k items at once, so the family-wise error rate is 1 - w^k. Decisions should come from the corrected p-value instead (RMitemRestscore with p_value = NULL and the full object returned here).

dgp

Character. Data-generating process for the parametric bootstrap. "conditional" (default) simulates each respondent's pattern from the exact Rasch conditional distribution given their observed total score, item parameters fixed (a conditional null). The expected gamma is computed from the observed score distribution, which the conditional null holds fixed. "resample" resamples WLE person locations with replacement and simulates responses under the model (a marginal null). In simulation under a true Rasch model, the conditional null gave a family-wise rate of 5.0 percent with correction = "fwer" and the resample null 6.4 percent, pooled over four designs. The conditional null takes about 1.2 to 1.6 times as long. Experimental.

Details

The asymptotic test in iarm::item_restscore() divides the observed minus expected gamma by the standard error of the observed gamma alone. The expected gamma is estimated from the same data and correlates with the observed one, so that standard error is too large for the difference, and the difference is also biased upwards in small samples. Under a true Rasch model the resulting test is liberal for dichotomous items in small or mistargeted samples and conservative for polytomous items, in every case flagging too few underfitting items. The bootstrap null replaces the asymptotic reference distribution and absorbs both problems.

The generating model is CML item parameters (via psychotools) with WLE person locations. For each iteration a dataset is simulated under the chosen dgp, the model is refitted by CML (psychotools::pcmodel()), and the observed and expected item-restscore gamma are computed as in iarm::item_restscore(), by a faster internal routine that skips the standard errors and the rounding of the printed values. The refit matters: the expected gamma varies from sample to sample because the thresholds do, and holding them fixed would reproduce the problem the bootstrap exists to solve. Failed iterations (e.g., degenerate simulated data) are silently discarded.

Parallel processing is provided by the mirai package (optional). Install it with install.packages("mirai") to enable parallelisation.

The iarm package must be installed (it is in Suggests, not Imports).

Value

A list with components:

results

data.frame with columns iteration, Item, Observed, Expected, Difference (one row per item per successful iteration). Difference is Observed - Expected, the statistic RMitemRestscore tests.

item_cutoffs

data.frame with per-item interval bounds for the difference: Item, diff_low, diff_high. Bounds are computed using the method specified by cutoff_method.

actual_iterations

Number of successful iterations. Everything downstream rests on this rather than on iterations, so it is the number to report.

requested_iterations

The iterations argument, kept so callers can tell how many simulated datasets were discarded.

sample_n

Number of complete cases used.

sample_n_total

Number of respondents in the raw input data, before the complete-case filter.

sample_has_na

Logical. Whether the raw input data contained any missing values.

sample_summary

Summary statistics of estimated person parameters.

item_names

Character vector of item names from data.

cutoff_method

The method used to compute the intervals ("hdci" or "quantile").

hdci_width

The HDCI width used (only meaningful when cutoff_method = "hdci").

dgp

The data-generating process used ("resample" or "conditional").

References

Kreiner, S. (2011). A Note on Item-Restscore Association in Rasch Models. Applied Psychological Measurement, 35(7), 557-561. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1177/0146621611410227")}

Johansson, M. (2026). Simulation-based cutoffs for conditional item fit in Rasch models: Iterations, multiplicity correction, and decision stability. PsyArXiv. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.31234/osf.io/7pqz4_v2")}

See Also

RMitemRestscore, RMitemRestscorePlot

Examples


if (requireNamespace("iarm", quietly = TRUE) &&
    requireNamespace("ggdist", quietly = TRUE)) {
  set.seed(42)
  sim_data <- as.data.frame(
    matrix(sample(0:1, 200 * 10, replace = TRUE), nrow = 200, ncol = 10)
  )
  colnames(sim_data) <- paste0("Item", 1:10)

  # Run 100 iterations sequentially for a quick demo
  cutoff_res <- RMitemRestscoreCutoff(sim_data, iterations = 100,
                                      parallel = FALSE, seed = 42)
  cutoff_res$item_cutoffs

  # Flag on bootstrap p-values in RMitemRestscore()
  RMitemRestscore(sim_data, cutoff = cutoff_res)
}


easyRasch2 documentation built on Oct. 6, 2026, 5:06 p.m.