View source: R/local_dependence.R
| RMlocdepQ3 | R Documentation |
Q_3 Residual Correlations for Local Dependence AssessmentComputes Yen's Q_3 residual correlations between item pairs. By default
the Rasch model is fitted by conditional maximum likelihood with WLE person
locations (estimator = "CML"); marginal ML via mirt is available with
estimator = "MML". High correlations (above the dynamic cut-off) indicate
potential local dependence between items. See RMlocdepQ3Cutoff
for how to determine the appropriate dynamic cut-off for your data.
RMlocdepQ3(
data,
cutoff = NULL,
output = "kable",
n_pairs = NULL,
p_value = NULL,
correction = c("fwer", "fdr_bh", "fdr_by", "none"),
alpha = 0.05,
estimator = c("CML", "MML")
)
data |
A data.frame or matrix of item responses. Items must be scored
starting at 0 (non-negative integers). Missing values ( |
cutoff |
Optional. |
output |
Character string controlling the return value. Either
|
n_pairs |
Integer or |
p_value |
Logical or |
correction |
Character. Multiple-comparison correction across item
pairs when |
alpha |
Numeric in (0, 1). Significance level for |
estimator |
Character. Estimation engine for the |
The Q_3 statistic (Yen, 1984) is the correlation between residuals of pairs
of items after accounting for the latent trait. Under local independence,
Q_3 values are expected to be around -1/(k-1) where k is the
number of items. When cutoff is supplied, the dynamic cut-off is the mean
of all off-diagonal Q_3 values plus cutoff, following the approach of
Christensen et al. (2017). Use RMlocdepQ3Cutoff to obtain a
simulation-based cutoff recommendation.
Q_3 is the column-wise correlation matrix of the model standardized
residuals (x - E)/\sqrt{Var}. By default (estimator = "CML") item
parameters are estimated by conditional maximum likelihood (psychotools)
and person locations by Warm's weighted likelihood; estimator = "MML"
instead uses mirt's marginal-ML model and its built-in Q_3 residuals.
The two estimators give very similar Q_3 values (off-diagonal correlation
typically > 0.95); what matters for inference is that the observed Q_3 and
the simulated cut-off in RMlocdepQ3Cutoff use the same
estimator, which the functions enforce.
Two views of local dependence. Given the full
RMlocdepQ3Cutoff object, two complementary tables are returned.
The $matrix applies a single global cut-off (the Christensen et al.
approach: the 99th percentile of the simulated max-minus-mean Q_3) – a
family-wise "is there any local dependence" overview. The $pairs table is
the per-comparison view: each observed Q_3 against its own simulated expected
range (the Low/High bounds), so individual dependent pairs can be read
off and ranked.
Bootstrap p-values. When p_value = TRUE, the $pairs table also
tests each observed Q_3 against its simulated null (from cutoff$pair_results)
with a one-sided (upper-tail) test for excess local dependence. The pair
statistic is studentised by the bootstrap mean and SD; the marginal p-value
is (1 + #{Q3* >= Q3}) / (B + 1), and correction applies the family-wise
(Westfall-Young step-down) or FDR adjustment across the k(k-1)/2 pairs.
As for item fit, the family-wise correction is liberal below 400
iterations in RMlocdepQ3Cutoff(), which is reported once per session,
and between 400 and 1000 the table caption notes that decisions remain
somewhat seed-dependent. A false discovery rate correction needs far more
iterations than the family-wise one, because a bootstrap p-value cannot
fall below 1/(B + 1) and Benjamini-Hochberg compares the smallest against
alpha/m. Over the 36 pairs of a nine-item scale that takes 720
iterations, and over the 190 pairs of a twenty-item scale 3799, against 19
for Westfall-Young whatever the number of pairs.
With cutoff = NULL or a bare numeric cut-off, a single object (kable or
data.frame) holding the lower triangle of the Q_3 matrix; a numeric cut-off
adds a Flagged row flag and a caption describing the dynamic
cut-off.
With the full RMlocdepQ3Cutoff() object, a named list of two:
$matrixthe Q_3 lower-triangle matrix with the global dynamic
cut-off (mean off-diagonal Q_3 + suggested cut-off), as above.
$pairsone row per item pair: Item1, Item2, Observed (Q_3),
Low/High (the per-pair expected range, i.e. the simulated bounds),
and Flagged – "above" (Q_3 above the upper bound, indicating local
dependence), "below" (below the lower bound), or "". Sorted by
absolute departure from the per-pair simulated median and truncated to
n_pairs. With p_value = TRUE, columns p_q3 and padj_q3 are added
and Flagged reflects padj_q3 < alpha and only flags "above".
The Q_3 tile heatmap that earlier versions returned as $plot is now produced
by RMlocdepQ3Plot (as its $matrix element), so the table and
plot outputs share the same $matrix/$pairs structure.
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.
Yen, W. M. (1984). Effects of local item dependence on the fit and equating performance of the three-parameter logistic model. Applied Psychological Measurement, 8(2), 125–145. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1177/014662168400800201")}
Christensen, K. B., Makransky, G., & Horton, M. (2017). Critical values
for Yen's Q_3: Identification of local dependence in the Rasch model.
Applied Psychological Measurement, 41(3), 178–194.
\Sexpr[results=rd]{tools:::Rd_expr_doi("10.1177/0146621616677520")}
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")}
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")}
# Simulate binary item response data (10 items, 200 persons)
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)
# Raw Q3 matrix (no cutoff)
RMlocdepQ3(sim_data)
# Get the underlying data.frame
q3_df <- RMlocdepQ3(sim_data, output = "dataframe")
# Simulation-based cutoff (use 500+ iterations in real analyses)
if (requireNamespace("ggdist", quietly = TRUE)) {
cutoff_res <- RMlocdepQ3Cutoff(sim_data, iterations = 50, parallel = FALSE)
# Bare numeric cutoff -> just the matrix
RMlocdepQ3(sim_data, cutoff = cutoff_res$suggested_cutoff)
# Full object -> list of two tables: $matrix and $pairs
res <- RMlocdepQ3(sim_data, cutoff = cutoff_res, output = "dataframe")
res$pairs
# Top 5 pairs, with bootstrap p-values (use iterations >= 1000 in practice)
RMlocdepQ3(sim_data, cutoff = cutoff_res, n_pairs = 5, p_value = TRUE,
output = "dataframe")$pairs
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.