easyRasch2 is an R package for Rasch measurement theory
analysis workflows. It is the successor to easyRasch,
offering a lightweight and consistent structure with proper namespacing
and minimal dependencies.
A central design choice is simulation-based critical values for various fit statistics. Rather than relying on rule-of-thumb cutoffs, most diagnostics are paired with a parametric-bootstrap function that generates an empirical null distribution from the fitted Rasch / PCM model and the observed sample.
The Get
Started link above contains a short introduction. For broader
Rasch-analysis tutorials, see the vignette
for the archived sibling package easyRasch.
A complete Rasch analysis requires many separate procedures — item fit, local dependence, dimensionality, differential item functioning, reliability, targeting, and more. In R these are spread across packages with differing data formats, argument conventions, and output objects, which raises the barrier to entry and can make analyses hard to reproduce. A further problem is that fit statistics (item fit MSQ, Yen’s \(Q_3\) residuals, the first residual-PCA contrast, CFA fit indices) are usually judged against fixed rule-of-thumb cutoffs that are known to depend on sample size, number of items and other factors such as targeting, and the number of response categories.
easyRasch2 targets applied researchers and students
validating rating scales and tests in health, education, and psychology
using modern psychometric methods. It provides a single, consistently
named interface across the whole workflow with publication-ready output,
and — as its distinguishing feature — replaces rule-of-thumb cutoffs
with sample-specific critical values obtained by parametric bootstrap
from the fitted Rasch/PCM model (Johansson, 2025). Several methods,
including the polytomous Martin-Löf test with Monte Carlo
p-values (Christensen & Kreiner, 2007) and the bootstrap
item-restscore test, are not available in other R packages.
Install from CRAN:
install.packages("easyRasch2")Install the development version from GitHub:
# install.packages("remotes") # if needed
remotes::install_github("pgmj/easyRasch2")psychotools and Warm’s Weighted Likelihood Estimation (WLE)
for person parameters. eRm is used for Andersen’s LR test
(RMdifLR()); mirt (MML) is available as an
optional engine (estimator = "MML" in
RMlocdepQ3() and RMitemParameters()) and for
the plausible values behind the RMU reliability metric.p_value = TRUE)
using Westfall–Young family-wise correction (default) or FDR
alternatives (Ferreira, 2024).knitr::kable() for tables
(Quarto-friendly), ggplot2 for figures, and
"dataframe" output options for downstream use. Every
caption reports the estimation sample size and missing-data policy.RM prefix
(e.g., RMlocdepQ3()).RMitemInfit() — conditional infit MSQ; optional
bootstrap p-values (p_value = TRUE) with
family-wise (Westfall–Young) or FDR multiple-comparison correctionRMitemInfitCutoff() + RMitemInfitPlot() —
simulation-based cutoffs and plotRMitemInfitMI() + RMitemInfitCutoffMI() —
multiple-imputation variantsRMitemRestscore() — item-restscore with
Goodman-Kruskal’s \(\gamma\)
(gamma)RMitemRestscoreBoot() — non-parametric bootstrap of
item-restscore fitRMitemICCPlot() - conditional item characteristic
curvesRMlocdepQ3() + RMlocdepQ3Cutoff() +
RMlocdepQ3Plot() — Yen’s \(Q_3\) residual correlations (CML/WLE by
default, estimator = "MML" optional); table and plot share
a $matrix (\(Q_3\)
heatmap) / $pairs (per-pair observed-vs-simulated)
structure; optional per-pair bootstrap p-valuesRMlocdepGamma() + RMlocdepGammaCutoff() +
RMlocdepGammaPlot() — partial-\(\gamma\) local dependence; optional
per-pair bootstrap p-valuesRMdimResidualPCA() +
RMdimResidualPCACutoff() — PCA of standardized residuals,
with simulation-based first-contrast cutoff (Chou & Wang, 2010) and
an optional bootstrap p-valueRMdimMartinLof() +
RMdimMartinLofResiduals() — Martin-Löf LR test (Christensen
& Kreiner, 2007), supports polytomous data with Monte Carlo
p-valuesRMdimCFACutoff() + RMdimCFA() +
RMdimCFAPlot() — posterior-predictive CFA fit-index and
per-item loading checks under PCM unidimensionality (via
lavaan WLSMV) with simulation-based cutoffs and optional
bootstrap p-valuesRMdifLR() — Andersen’s likelihood-ratio test
(eRm::LRtest)RMdifTree() — Rasch / partial-credit trees
(psychotree) with Mantel-Haenszel or partial-\(\gamma\) effect sizes per split, optional
iterative purification, and stablelearner-based stability
assessmentRMdifGamma() + RMdifGammaCutoff() +
RMdifGammaPlot() — partial-\(\gamma\) DIF; optional bootstrap
p-values calibrated against the simulated Rasch nullRMitemICCPlot() - evaluates DIF across class
intervalsRMitemCatProb() for classic item probability function
trace plots.RMitemHierarchy() renders a plot sorting items based on
difficulty, showing item threshold locations and confidence
intervals.RMreliability() + RMUreliability() —
Cronbach’s α, PSI, marginal reliability, and Relative Measurement
Uncertainty from plausible valuesRMtargeting() — Wright-map style person-item targeting
plotRMscoreSE() — raw-score → logit transformation table
(WLE / EAP)RMitemParameters() — item difficulty / threshold
locations in long or wide format, with optional standard errors and
confidence intervals (CML via psychotools, or MML via
mirt for sparse data)RMpersonParameters() — per-respondent person locations
(WLE or EAP), estimated on each response pattern so partial missingness
is handled directlyRMpersonFit() — per-respondent conditional infit /
outfit MSQ and the standardized log-likelihood \(\ell_z\), with resampling-based
p-values rather than unreliable asymptotic nulls (Sinharay,
2016; Müller, 2020)RMplotTile() — response-distribution heatmap with
optional group facetingRMplotBar() & RMplotStackedbar()library(easyRasch2)
data("pcmdat2", package = "eRm")
options(mc.cores = 4)
set.seed(42)
# Conditional item infit with simulation-based cutoffs
simfit <- RMitemInfitCutoff(pcmdat2, iterations = 250)
RMitemInfit(pcmdat2, cutoff = simfit)
# Test of unidimensionality via posterior-predictive ordinal CFA
cfa_sim <- RMdimCFACutoff(pcmdat2, iterations = 250) # simulated reference
tabs <- RMdimCFA(pcmdat2, cutoff = cfa_sim) # observed vs expected
tabs$fit # fit-index table
tabs$loadings # per-item loading table
plots <- RMdimCFAPlot(cfa_sim, data = pcmdat2) # list of 2 ggplots
plots$loadings # observed vs expected loadings
plots$fit # fit-index distributions
# DIF analysis via Andersen's LR test
grp <- factor(sample(c("A", "B"), nrow(pcmdat2), replace = TRUE))
RMdifLR(pcmdat2, dif_var = grp)
# Rasch-tree DIF with effect-size classification on continuous +
# categorical covariates simultaneously
covs <- data.frame(
group = grp,
band = sample(c("low", "high"), nrow(pcmdat2), replace = TRUE)
)
RMdifTree(pcmdat2, covariates = covs)As mentioned earlier, this is based on my easyRasch
package, and I am using Claude Opus/Fable to rewrite functions to this
more properly formatted package. While it uses my earlier code, most of
the code in this package is produced by the LLM and tested and bug fixed
by me.
RMdifTree() adapts MIT-licensed code from Mirka
Henninger and Jan Radek’s raschtreeMH
and effecttree
packages for the effect-size and ETS-classification algorithms.
Magnus Johansson is a licensed psychologist with a PhD in behavior analysis. He works as a research specialist focused on psychometrics and statistics at Karolinska Institutet, Department of Clinical Neuroscience, Center for Psychiatry Research.
GPL (>= 3)