View source: R/conditional_infit.R
| RMitemInfit | R Documentation |
Computes conditional infit mean-square (MSQ) statistics for each item using
iarm::out_infit(), enriched with item locations relative to the sample
mean person location.
RMitemInfit(
data,
cutoff = NULL,
p_value = NULL,
correction = c("fwer", "fdr_bh", "fdr_by", "none"),
alpha = 0.05,
output = "kable",
sort,
statistic = "infit"
)
data |
A data.frame or matrix of item responses. Items must be scored
starting at 0 (non-negative integers). Missing values ( |
cutoff |
Optional. Default
|
p_value |
Logical or
With Up to and including version 1.1.1 the default was |
correction |
Character. Multiple-comparison correction applied across
items when |
alpha |
Numeric in (0, 1). Significance level for the |
output |
Character string controlling the return value. Either
|
sort |
Optional character string. When |
statistic |
Character string. Which conditional fit statistic the table
reports: |
Infit MSQ is a weighted fit statistic that emphasises deviations near the
item location. Values close to 1.0 indicate good fit. Values substantially
above 1.0 suggest underfit (unexpected responses), while values substantially
below 1.0 suggest overfit (overly predictable responses). The definition of
"substantially" depends on several factors such as sample size, and needs to
be determined by simulation using RMitemInfitCutoff. There is no general
rule-of-thumb value that is correct.
Conditional infit MSQ statistics are computed via iarm::out_infit(), which
uses the conditional distribution of the sufficient statistics (Müller, 2020).
Only complete cases (rows without any NA) are used in the conditional fit
calculation.
Item parameters are estimated by conditional maximum likelihood via
psychotools::pcmodel() (a dichotomous item is a 2-category PCM); the
conditional infit/outfit MSQ comes from iarm::out_infit() and is invariant
to the estimation engine. Per-item average locations are the means of the
CML thresholds, and the person-location reference is the mean of the Warm
WLE estimates.
Relative item location is defined as the item's average location minus the sample mean person location, providing a measure of item targeting.
The iarm package must be installed (it is in Suggests, not Imports).
Bootstrap p-values. When p_value = TRUE, each item's observed
infit (or outfit, per statistic) is compared against its simulated null
distribution (from cutoff$results). The per-item statistic is the residual studentised by
the bootstrap mean and SD – deliberately the empirical SD rather than the
Wilson-Hilferty / ZSTD transform, which is uninformative for conditional
MSQ (Müller, 2020). The marginal p-value is the two-sided Monte-Carlo
p-value (1 + #{|t*| >= |t|}) / (B + 1). For correction = "fwer" the
family-wise adjustment uses the Westfall-Young studentised-max step-down,
which exploits the bootstrap dependence among items and is more powerful
than Bonferroni/Holm (Ferreira, 2024); its validity rests on subset
pivotality. "fdr_bh"/"fdr_by" apply Benjamini-Hochberg / Benjamini-
Yekutieli instead. These are model-conditional, sample-size-sensitive
p-values and are reported alongside the simulated effect-size band, not in
place of it. p-values can be no smaller than 1 / (B + 1). Below 400
iterations in RMitemInfitCutoff() the studentised-max (FWER)
correction is mildly liberal, because the bootstrap mean and SD used for
studentisation are too noisy, and a message says so. From 400 iterations
the family-wise error rate is at the nominal level, and more iterations
improve reproducibility instead: two analysts using different seeds
disagree about at least one item roughly 10 percent of the time at 400
iterations against 4 percent at 2000 (Johansson, 2026). The table caption
notes this below 1000 iterations, so use 1000 to 2000 for a final
analysis. The marginal p-values are well calibrated even at a few hundred
iterations.
If output = "kable": a knitr_kable object (plain text table via
format = "pipe") with columns "Item", "Infit MSQ", and "Relative
location", and a caption showing the number of complete cases. When
cutoff is provided, columns "Infit low", "Infit high", and "Flagged"
are also included, and the caption notes the simulation-based cutoffs.
If output = "dataframe": a data.frame with columns Item,
Infit_MSQ, and Relative_location. When cutoff is provided, columns
Infit_low, Infit_high, and Flagged are also included (inserted
after Infit_MSQ, before Relative_location). Flagged is a character
column with values "overfit", "underfit", or "" (not the previous
logical). When p_value = TRUE, columns p_infit (marginal two-sided
p-value) and padj_infit (corrected p-value) are added and Flagged
reflects items with padj_infit < alpha (direction from Infit_MSQ
relative to 1).
With statistic = "outfit" the layout is identical and the column names
follow the statistic: Outfit_MSQ, Outfit_low, Outfit_high, p_outfit,
padj_outfit.
The marginal p-value controls the error rate of a single comparison: for
one item (or item pair) decided on in advance it is the relevant value. But
scanning all k comparisons and flagging whichever fall below alpha tests
k hypotheses at once, so the chance of at least one false flag inflates to
roughly 1 - (1 - \alpha)^k (e.g. about 34% for k = 8 at
alpha = 0.05) – even when every marginal p-value is correctly calibrated.
The corrected (adjusted) p-value controls this: correction = "fwer" bounds
the probability of any false flag (strict, lower power), while "fdr_bh" /
"fdr_by" bound the expected proportion of false flags among those raised
(a more lenient middle ground). Rule of thumb: use the marginal p-value for a
single pre-specified comparison, and a corrected p-value when screening the
whole table – the usual workflow.
Item infit and item-restscore both judge each item against expectations from a Rasch model fitted to all items, so misfitting items change what is expected of the others. A flag in one direction can therefore produce flags in the other. Overfitting items can push fitting items into the underfit range, and underfitting items, for example from a second dimension, can make fitting items look overfit. How large the effect is depends on how strong the misfit is and how many items share it. In simulation with seven polytomous items, two overfitting items led to about 6 percent of the fitting items being flagged as underfit, and one or two mildly multidimensional items to 1 to 2 percent being flagged as overfit. When items are flagged in both directions, consider removing the clearest misfit and testing again before interpreting the rest.
Müller, M. (2020). Item fit statistics for Rasch analysis: Can we trust them? Journal of Statistical Distributions and Applications, 7(5). \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1186/s40488-020-00108-7")}
Ferreira, J. A. (2024). Methods of testing a 'small' or 'moderate' number of hypotheses simultaneously. Journal of Statistical Theory and Practice, 19(6). \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1007/s42519-024-00412-4")}
Westfall, P. H., & Young, S. S. (1993). Resampling-Based Multiple Testing. Wiley.
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")}
RMitemInfitCutoff
if (requireNamespace("iarm", quietly = TRUE)) {
# Simulate binary item response data (5 items, 40 persons)
set.seed(42)
sim_data <- as.data.frame(
matrix(sample(0:1, 40 * 5, replace = TRUE), nrow = 40, ncol = 5)
)
colnames(sim_data) <- paste0("Item", 1:5)
# Default kable output
RMitemInfit(sim_data)
# Sorted by infit MSQ descending
RMitemInfit(sim_data, sort = "infit")
# Return as data.frame for further processing
df <- RMitemInfit(sim_data, output = "dataframe")
# Simulation-based cutoffs (100 Monte-Carlo iterations)
if (requireNamespace("ggdist", quietly = TRUE)) {
cutoff_res <- RMitemInfitCutoff(sim_data, iterations = 100,
parallel = FALSE, seed = 42)
RMitemInfit(sim_data, cutoff = cutoff_res)
RMitemInfit(sim_data, cutoff = cutoff_res, output = "dataframe")
# Bootstrap p-values with family-wise (Westfall-Young) correction
# (use iterations >= 1000 in real analyses for stable p-values)
RMitemInfit(sim_data, cutoff = cutoff_res, p_value = TRUE,
output = "dataframe")
# The same for conditional outfit MSQ
RMitemInfit(sim_data, cutoff = cutoff_res, p_value = TRUE,
statistic = "outfit", output = "dataframe")
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.