| ripd | R Documentation |
This function computes three RIPD statistics–RIPD_{R}, RIPD_{S},
and RIPD_{RS}–for each item. RIPD_{R} captures differences in
mean raw residuals between groups, which is typically indicative of uniform
item parameter drift (IPD). RIPD_{S} captures differences in mean
squared residuals between groups, reflecting nonuniform IPD. RIPD_{RS},
a combined chi-square-based index, is sensitive to both uniform and
nonuniform IPD.
ripd(x, ...)
## Default S3 method:
ripd(
x,
data,
score = NULL,
group,
focal.name,
item.skip = NULL,
D = 1,
alpha = 0.05,
missing = NA,
purify = FALSE,
purify.by = c("ripdrs", "ripdr", "ripds"),
max.iter = 10,
min.resp = NULL,
method = "ML",
range = c(-5, 5),
norm.prior = c(0, 1),
nquad = 41,
weights = NULL,
ncore = 1,
verbose = TRUE,
...
)
## S3 method for class 'est_irt'
ripd(
x,
score = NULL,
group,
focal.name,
item.skip = NULL,
alpha = 0.05,
missing = NA,
purify = FALSE,
purify.by = c("ripdrs", "ripdr", "ripds"),
max.iter = 10,
min.resp = NULL,
method = "ML",
range = c(-5, 5),
norm.prior = c(0, 1),
nquad = 41,
weights = NULL,
ncore = 1,
verbose = TRUE,
...
)
## S3 method for class 'est_item'
ripd(
x,
group,
focal.name,
item.skip = NULL,
alpha = 0.05,
missing = NA,
purify = FALSE,
purify.by = c("ripdrs", "ripdr", "ripds"),
max.iter = 10,
min.resp = NULL,
method = "ML",
range = c(-5, 5),
norm.prior = c(0, 1),
nquad = 41,
weights = NULL,
ncore = 1,
verbose = TRUE,
...
)
x |
A data frame containing item metadata (e.g., item parameters,
number of categories, IRT model types, etc.); or an object of class
See |
... |
Additional arguments passed to the |
data |
A matrix of examinees' item responses corresponding to the items
specified in the |
score |
A numeric vector containing examinees' ability estimates (theta
values). If not provided, |
group |
A numeric or character vector indicating group membership of examinees. The length of the vector should be the same as the number of rows in the response data matrix. |
focal.name |
A single numeric or character value specifying the focal
group. For instance, given |
item.skip |
A numeric vector of item indices to exclude from IPD analysis. If NULL, all items are included. Useful for omitting specific items based on prior insights. |
D |
A scaling constant used in IRT models to make the logistic function closely approximate the normal ogive function. A value of 1.7 is commonly used for this purpose. Default is 1. |
alpha |
A numeric value specifying the significance level ( |
missing |
A value indicating missing values in the response data set. Default is NA. |
purify |
Logical. Indicates whether to apply a purification procedure.
Default is |
purify.by |
A character string specifying which RIPD statistic is used
to perform the purification. Available options are "ripdrs" for
|
max.iter |
A positive integer specifying the maximum number of
iterations allowed for the purification process. Default is |
min.resp |
A positive integer specifying the minimum number of valid
item responses required from an examinee in order to compute an ability
estimate. Default is |
method |
A character string indicating the scoring method to use. Available options are:
Default is |
range |
A numeric vector of length two specifying the lower and upper
bounds of the ability scale. This is used for the following scoring
methods: |
norm.prior |
A numeric vector of length two specifying the mean and
standard deviation of the normal prior distribution. These values are used
to generate the Gaussian quadrature points and weights. Ignored if |
nquad |
An integer indicating the number of Gaussian quadrature points
to be generated from the normal prior distribution. Used only when |
weights |
A two-column matrix or data frame containing the quadrature
points (in the first column) and their corresponding weights (in the second
column) for the latent variable prior distribution. The weights and points
can be conveniently generated using the function If |
ncore |
An integer specifying the number of logical CPU cores to use for
parallel processing. Default is |
verbose |
Logical. If |
Theoretical Background: From RDIF to RIPD
The RIPD framework directly adapts the residual-based differential item
functioning (RDIF) detection framework (Lim et al., 2022; Lim & Choe, 2023)
to detect item parameter drift (IPD) in computerized adaptive testing (CAT).
Each RIPD statistic (RIPD_R, RIPD_S, RIPD_{RS}) mirrors
its RDIF counterpart (RDIF_R, RDIF_S, RDIF_{RS}) in both
computation and asymptotic theory, with one key adaptation: whereas the
original RDIF framework estimates item parameters once from the pooled data
of both groups, the RIPD framework uses the original, pre-calibrated
item parameters from the CAT pool directly, eliminating the need for item
recalibration. This makes RIPD practically scalable for operational CAT
programs where recalibration is often infeasible due to sparse and
non-ignorably missing response data.
IPD in CAT can be viewed as a special case of DIF across time (Lord, 1980; Veerkamp & Glas, 2000): the focal group represents current test-takers whose responses may reflect drift, while the reference group represents a baseline under invariant item parameters.
Residual Definition
For examinee i and item j, the raw residual is defined as
e_{ij} = u_{ij} - P_j(\hat{\theta}_i),
where u_{ij} is the observed binary response (0 or 1) and
P_j(\hat{\theta}_i) is the model-predicted probability of a correct
response under the original item parameters evaluated at the
examinee's ability estimate \hat{\theta}_i. Because item responses
are independent but not identically distributed (due to varying predicted
probabilities across examinees with different ability levels), the asymptotic
distributions of the RIPD statistics are established via Lyapunov's central
limit theorem.
Three RIPD Statistics and Their Asymptotic Distributions
RIPD_R (uniform drift): Measures the difference in mean raw
residuals between the focal (F) and reference (R) groups,
RIPD_{R,j} = \frac{\sum_{i \in F} e_{ij}}{N_F} -
\frac{\sum_{i \in R} e_{ij}}{N_R}.
RIPD_{R,j} is most effective when the item response functions (IRFs)
of the two groups differ primarily in location (e.g., drift in the difficulty
b or guessing c parameter). Under the null hypothesis H_0
of no IPD, RIPD_{R,j} asymptotically follows a normal distribution
with mean zero and analytically derived variance
\sigma^2_{RIPD_R} = \frac{\sum_{i \in F} P_{ij}(1 - P_{ij})}{N_F^2} +
\frac{\sum_{i \in R} P_{ij}(1 - P_{ij})}{N_R^2}.
A standard Z-test is then applied as Z_R = RIPD_{R,j} / \sigma_{RIPD_R}.
RIPD_S (nonuniform drift): Measures the difference in mean
squared residuals between groups,
RIPD_{S,j} = \frac{\sum_{i \in F} e_{ij}^2}{N_F} -
\frac{\sum_{i \in R} e_{ij}^2}{N_R}.
RIPD_{S,j} captures drift that varies across the ability continuum,
such as a change in the discrimination parameter a, which
RIPD_{R,j} alone may not detect. Importantly, under H_0, the
null mean of RIPD_{S,j} is not zero in general; it equals
\mu_{RIPD_S} = \frac{\sum_{i \in F} P_{ij}(1 - P_{ij})}{N_F} -
\frac{\sum_{i \in R} P_{ij}(1 - P_{ij})}{N_R},
which is a function of the predicted probabilities in both groups and
vanishes only when their ability distributions are perfectly matched (as in
the RIPD setup where focal \hat{\theta} values are reused for the
synthetic reference group). The asymptotic variance is also analytically
derived. A standard Z-test is applied as
Z_S = (RIPD_{S,j} - \mu_{RIPD_S}) / \sigma_{RIPD_S}.
RIPD_{RS} (combined): A Wald-type statistic that jointly tests
for uniform and nonuniform drift within a single framework,
RIPD_{RS,j} = (\boldsymbol{\nu}_j - \boldsymbol{\mu}_j)^\top
\hat{\boldsymbol{\Sigma}}_j^{-1}
(\boldsymbol{\nu}_j - \boldsymbol{\mu}_j),
where \boldsymbol{\nu}_j = (RIPD_{R,j},\ RIPD_{S,j})^\top,
\boldsymbol{\mu}_j = (\mu_{RIPD_R},\ \mu_{RIPD_S})^\top is the
vector of null means, and \hat{\boldsymbol{\Sigma}}_j is the
analytically derived 2 \times 2 covariance matrix of
(RIPD_{R,j}, RIPD_{S,j}). Under H_0, RIPD_{RS,j}
asymptotically follows a \chi^2 distribution with 2 degrees of
freedom. RIPD_{RS} is the recommended statistic in practice
because it is sensitive to both uniform and nonuniform drift and addresses
potential inflation of the family-wise Type I error that arises from
applying RIPD_R and RIPD_S separately to the same item.
Diagnosing the Nature of Drift
The pattern of flagging across the three statistics can help diagnose the
type of drift. If an item is flagged by RIPD_R (and possibly
RIPD_{RS}) but not RIPD_S, uniform drift is indicated (e.g.,
difficulty shift). If flagged by RIPD_S (and possibly
RIPD_{RS}) but not RIPD_R, nonuniform drift is suggested (e.g.,
discrimination change). Items flagged by all statistics or by
RIPD_{RS} alone likely exhibit mixed drift.
CAT-Specific Workflow
The RIPD procedure for CAT consists of three steps (Lim & Han, in press):
Focal group CAT: The current cohort of examinees takes the
CAT using the operational (potentially drifted) item pool. Each examinee
receives only a subset of items; the resulting response matrix is sparse.
The ML ability estimates \hat{\theta} from this step are retained.
Synthetic reference group construction: The focal group's
\hat{\theta} values are treated as true abilities. Item responses
are generated from the original (pre-calibrated, drift-free) item
parameters, and an independent CAT is administered. This creates a
synthetic reference group that matches the focal group's ability
distribution, so that any systematic differences in residuals can be
attributed to IPD rather than ability confounds. The reference group
size is controlled by a replication factor: e.g., 1F reuses the focal
\hat{\theta} values once (N_ref = N_foc), while kF replicates them
k times. Larger reference groups (3F-8F) reduce sampling variability in
reference residuals and improve detection power, with marginal gains
typically diminishing beyond 5F.
RIPD computation with purification: Residuals are computed
for both groups using the original item parameters, and the three RIPD
statistics are evaluated item-by-item. Items whose Z-test (for
RIPD_R or RIPD_S) or chi-square test (for
RIPD_{RS}) exceeds the critical value at level alpha are
flagged as drifting.
Purification Procedure
When purify = TRUE, an iterative purification procedure adapted from
Lim et al. (2022) is applied to mitigate the bias in ability estimates caused
by drifted items–analogous to the contaminating effect of DIF items on
matching variables. At each iteration:
The item with the most statistically significant drift statistic (smallest p-value) among currently unflagged items is identified and flagged as a potential IPD item.
Ability estimates are recomputed excluding all currently flagged items.
RIPD statistics are recalculated using the updated ability estimates for the remaining items.
The process continues until no additional items are flagged (convergence) or
the maximum number of iterations (max.iter) is reached. The statistic
used to drive purification is specified by purify.by;
"ripdrs" (RIPD_{RS}) is recommended as it is sensitive to both
types of drift.
Key Items and item.skip
In CAT contexts, many items in the pool receive few responses and thus lack
sufficient data for reliable IPD analysis. The item.skip argument
allows users to exclude such items (e.g., low-exposure non-key items) from
the analysis. In practice, key items for RIPD evaluation are typically
identified through a preliminary CAT simulation as those with the highest
average exposure frequencies under the intended operational settings.
This function returns a list containing four main components:
no_purify |
A list of sub-objects containing the results of IPD analysis without applying a purification procedure. The sub-objects include:
|
purify |
A logical value indicating whether the purification procedure was applied. |
with_purify |
A list of sub-objects containing the results of IPD analysis with a purification procedure. The sub-objects include:
|
alpha |
A numeric value indicating the significance level ( |
ripd(default): Default method for computing the three RIPD statistics using
a data frame x that contains item metadata
ripd(est_irt): An object created by the function est_irt().
ripd(est_item): An object created by the function est_item().
Hwanggyu Lim hglim83@gmail.com
Lim, H., & Choe, E. M. (2023). Detecting differential item functioning in CAT using IRT residual DIF approach. Journal of Educational Measurement, 60(4), 626-650. \Sexpr[results=rd]{tools:::Rd_expr_doi("doi:10.1111/jedm.12366")}.
Lim, H., Choe, E. M., & Han, K. T. (2022). A residual-based differential item functioning detection framework in item response theory. Journal of Educational Measurement, 59(1), 80-104. \Sexpr[results=rd]{tools:::Rd_expr_doi("doi:10.1111/jedm.12313")}.
Lim, H., & Han, K. T. (in press). IRT residual-based approach to detecting item parameter drift in CAT. Journal of Educational and Behavioral Statistics.
rdif(), est_irt(), est_item(),
simdat(), shape_df(), est_score()
## --- RIPD Example: Detecting IPD in CAT ---------------------------------
##
## Background (Lim & Han, in press):
## In CAT-based IPD detection using RIPD, the reference group is
## "synthetic" -- created by re-administering a CAT to examinees whose
## true abilities are set equal to the focal group's ML theta estimates,
## using the ORIGINAL (pre-drift) item parameters. This eliminates the
## need for recalibration and makes RIPD directly applicable to
## operational CAT settings.
##
## The simIPD dataset contains:
## - foc_resp / foc_score : focal group CAT responses + ML theta estimates
## (IPD items: a and b each drifted by -0.5)
## - ref_resp / ref_score : synthetic reference group CAT responses + ML
## theta estimates (original parameters, 1F size)
## - item_par : original (non-drifted) 360-item pool in irtQ format
## - key_item : indices of 90 key items (highly exposed in CAT)
## - item.skip : indices of 270 non-key items (excluded from RIPD)
## - ipd_item : indices of 18 truly drifted items (ground truth)
## -------------------------------------------------------------------------
data(simIPD)
## Step 1. Combine focal and synthetic reference group data
## (reference group first, then focal group -- as in the paper)
data <- rbind(simIPD$ref_resp, simIPD$foc_resp)
score <- c(simIPD$ref_score, simIPD$foc_score)
group <- c(rep(0, nrow(simIPD$ref_resp)), # 0 = reference
rep(1, nrow(simIPD$foc_resp))) # 1 = focal
## Step 2. Run RIPD with purification (recommended statistic: RIPD_RS)
## item.skip excludes the 270 non-key items from analysis
ripd_result <- ripd(
x = simIPD$item_par,
data = data,
score = score,
group = group,
focal.name = 1, # focal group is coded as 1
item.skip = simIPD$item.skip,
D = 1.7,
alpha = 0.05,
purify = TRUE,
purify.by = "ripdrs", # purify using RIPD_RS (combined statistic)
max.iter = 30,
method = "ML",
range = c(-5, 5)
)
## Step 3. Review RIPD_RS results (with purification)
print(ripd_result, what = "with_purify")
## Step 4. Compare detected items to ground truth
detected <- ripd_result$with_purify$ipd_item
cat("Truly drifted items (ground truth):", simIPD$ipd_item, "\n")
cat("RIPD-detected items: ", detected, "\n")
cat("True positives:", sum(detected %in% simIPD$ipd_item), "of",
length(simIPD$ipd_item), "\n")
## -- Note on reference group size -----------------------------------------
## This example uses a 1F reference group (n_ref = n_foc = 3,000).
## In practice, a larger reference group (3F-8F) substantially improves
## detection power. To create a 3F reference group, replicate the focal
## theta estimates and re-run the CAT simulation with original parameters:
##
## theta_3F <- rep(simIPD$foc_score, times = 3) # 9,000 examinees
## resp_3F <- simdat(x = simIPD$item_par, theta = theta_3F, D = 1.7)
## # ... then run CAT and call ripd() with the larger reference group
## -------------------------------------------------------------------------
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.