View source: R/person_change.R
| RMpersonChange | R Documentation |
Tests, for each respondent, whether their person location moved between two
occasions by more than measurement error allows. The statistic is the Rasch
change index, RCI = (\hat\theta_2 - \hat\theta_1)/SE_{diff}, referred
by default to a simulated rather than a normal null.
RMpersonChange(
data_t1,
data_t2,
id = NULL,
anchor = "stack",
item_params = NULL,
method = "WLE",
estimator = "CML",
null = "measurement",
retest_sd = NULL,
critical = "exact",
alpha = 0.05,
direction = "two.sided",
conditional_crit = FALSE,
sim_iter = 1000,
parallel = TRUE,
n_cores = NULL,
seed = NULL,
theta_range = c(-10, 10),
verbose = FALSE,
output = "dataframe"
)
data_t1, data_t2 |
Data.frames or matrices of item responses at the two
occasions. Same items, in the same order, one row per respondent, with row
|
id |
Optional vector of respondent identifiers, length |
anchor |
Character. Where the item calibration comes from: |
item_params |
Optional pre-specified item parameters, either a named
list of Andrich-threshold vectors or the long-format data.frame from
|
method |
Character. Person-location estimator, |
estimator |
Character. How item parameters are estimated when
|
null |
Character. Which null hypothesis is tested. |
retest_sd |
Numeric, or |
critical |
How the critical values are obtained. |
alpha |
Numeric in (0, 1). Error rate for a single respondent. Default
|
direction |
Character. |
conditional_crit |
Logical. If |
sim_iter |
Integer. Simulation iterations when
|
parallel |
Logical. Use |
n_cores |
Integer or |
seed |
Integer or |
theta_range |
Numeric length 2. Search range for the WLE root and
bounds for the EAP grid. Default |
verbose |
Logical. Print a progress bar for the simulation. Default
|
output |
Character. |
Which null is tested. Following Zumbo (2026), the estimand is fixed by what counts as systematic and what counts as residual, and that choice has to be made before an estimator is picked. Two are available here:
null = "measurement", the default. The respondent's \theta is
fixed and identical at both occasions and only the response process is
random, so SE_{diff}^2 = SE_1^2 + SE_2^2. This asks whether the two
estimates differ by more than responding alone would produce.
null = "retest". Occasion-to-occasion fluctuation that is not change in
the construct (state, mood, recall, practice) also counts as noise, so
SE_{diff}^2 = SE_1^2 + SE_2^2 + 2\sigma^2_{retest}. The factor of 2
is there because retest_sd is a per-occasion SD and both occasions
carry one.
The default is the narrower of the two, so it flags more change than a
retest-based null would. It is the only one computable from two response
vectors alone, which is why it is the default, but a significant result
under it is a necessary condition for change rather than evidence of it.
retest_sd_tip reports, for each flagged respondent, how large
\sigma_{retest} would have to be to overturn their result.
Caronni et al. (2026) compute 1.96\sqrt{SE_A^2 + SE_B^2} from the
Rasch score-to-measure map and call it a minimal detectable change. That is
the null = "measurement" quantity, whereas the classical MDC is built from
a test-retest ICC and is the null = "retest" quantity. The two are not
interchangeable, which is why the null in force is named in every caption
here.
Regression to the mean is present under both nulls and is addressed by neither. A regression-based reliable change index (Maassen, 2004) is out of scope for a single-subject function, since it needs population parameters the individual case does not supply.
Why 1.96 is the wrong cutoff. The sum score is a sufficient statistic,
so \hat\theta takes only as many values as there are scores, and
SE(\hat\theta) is a deterministic function of the score rather than a
constant. The denominator of the RCI is therefore not independent of its
numerator: a respondent who moves to an extreme score produces a large
change and a large standard error together, and the ratio is damped. Both
tails of the null are pulled in, so the critical value sits below 1.96, and
the shortfall grows as the scale shortens. Enumerated values for one family
of items with four response categories: 1.62 at four items, 1.70 at six,
1.79 at ten, 1.85 at twenty, 1.92 at forty. Response categories matter much
less than item count here, and almost all of their effect is the step from
dichotomous to polytomous: at six items the value moves from 1.55 with two
categories to 1.72 with three and only 1.78 with seven, while reliability
over the same range climbs from about .60 to about .91. Referring the RCI to
a normal null is conservative, and materially so on short scales.
How the null is obtained. critical = "exact" enumerates it. Because
the score is sufficient, \hat\theta(r) and SE(r) are
deterministic lookups and P(r \mid \theta) follows from the
Lord-Wingersky recursion, so the null is a discrete distribution over score
pairs with no Monte Carlo error. Respondents are grouped by their pair of
answered-item sets, so incomplete data is enumerated within each pattern.
Under null = "retest" the occasion deviations are integrated out by
quadrature. critical = "simulate" estimates the same distribution by
drawing response vectors instead, which is slower and noisier but makes no
use of sufficiency.
Quantiles are taken from the signed RCI, so crit_lower and
crit_upper are reported separately. Under the null the two occasions are
exchangeable, which makes the RCI symmetric about zero however skewed
\hat\theta itself is, and the two bounds then agree in magnitude.
They part company when exchangeability fails, most commonly when the
occasions differ in which items were answered.
The pooled critical value is a property of the sample as well as the items, because it averages over where the respondents sit. Targeting matters more than the shape of the distribution: skewing the sample barely moves it, while pushing the same sample off target until 40 percent of respondents score at an extreme moved it from 1.70 to 1.52 in one check.
What the RCI measures, and what it does not. The RCI answers whether a change is distinguishable from the null. It is not a measure of how much someone changed, and the two orderings genuinely differ. Its value mixes two ingredients that it cannot separate: how far the respondent moved, and how precisely each of their two positions was pinned down. On a scale of six items with four response categories the standard error runs from 0.49 in the middle to 1.45 at the boundary, a factor of three within one instrument. A respondent going from the minimum to the maximum score moves 7.24 logits and scores RCI 3.53, while one going from 3 to 15 moves 3.11 logits and scores 3.59. The first traversed the whole scale, the second less than half of it, and the second has the larger statistic. Both statements are correct about their own question.
In a group comparison every case shares one standard error, so ordering by
the test statistic matches ordering by effect. Here the scale factor changes
from respondent to respondent, and the output is read one person at a time,
which is where the misreading does damage. Read change for magnitude, in
logits, and rci only for the decision. Do not rank respondents by rci,
and do not compare RCIs across instruments or across regions of one scale as
though they were a common currency.
Simulating fixes the reference distribution, not the estimand. A simulated
critical value under null = "measurement" is a well calibrated answer to
the measurement-error question, not to the retest question.
Calibration and its precondition. anchor = "stack" calibrates on both
occasions row-bound together. It uses all the data and puts both occasions
on one metric by construction, at the cost of assuming the items behave the
same way on both occasions. When they do not, the compromise calibration
pulls the occasions toward each other and shrinks apparent change. Test that
precondition first with the package's DIF tools, using occasion as the
grouping variable on the stacked data. anchor = "t1" measures follow-up on
the baseline metric and keeps post-treatment data out of it, at the cost of
halving the calibration sample. "t2" is the mirror.
Note that stacking puts each respondent in the data twice, so the item parameters' own standard errors are optimistic. That does not propagate into the person standard errors, which treat the thresholds as fixed.
retest_sd_tip. For a respondent whose change is flagged, this is the
per-occasion retest SD that would bring their RCI back to the critical
value, \sigma^2_{tip} = (\mathrm{change}^2/c^2 - SE_1^2 - SE_2^2)/2.
It is NA for respondents not flagged, for whom the question does not
arise. The critical value is held fixed at the one in force, which is exact
when critical is numeric and an approximation when it is simulated, since
a simulated critical value drifts toward \pm 1.96 as the added normal
component smooths the discreteness.
If output = "dataframe": one row per respondent, with columns id,
sum_t1, sum_t2, theta_t1, se_t1, theta_t2, se_t2,
extreme_t1, extreme_t2, change, se_diff, rci, p_value,
crit_lower, crit_upper, change_class, and retest_sd_tip.
Attributes null, retest_sd, anchor, alpha, direction,
critical and sim_iter record the analysis.
If output = "kable": the same content as a knitr_kable.
If output = "ggplot": occasion 1 against occasion 2, with the
no-change band and points coloured by change_class.
Caronni, A., et al. (2026). Improving single-subject change assessment: deriving the minimal detectable change of questionnaires' ordinal scores from the Rasch analysis measures.
Jacobson, N. S., & Truax, P. (1991). Clinical significance: A statistical approach to defining meaningful change in psychotherapy research. Journal of Consulting and Clinical Psychology, 59(1), 12-19. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1037/0022-006X.59.1.12")}
Maassen, G. H. (2004). The standard error in the Jacobson and Truax Reliable Change Index. Journal of Clinical and Experimental Neuropsychology, 26(5), 643-657. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1080/13803390409609791")}
Zumbo, B. D. (2026). Conditional standard error of measurement as an estimand of individual score precision. Psychometrika. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1017/psy.2026.10141")}
RMretestSD(), RMpersonParameters(), RMreliabilityCurve(),
RMscoreSE()
set.seed(1)
thr <- lapply(seq(-1.2, 1.2, length.out = 6), function(b) b + c(-0.8, 0, 0.8))
theta <- rnorm(80, 0, 1.4)
t1 <- as.data.frame(easyRasch2:::sim_partial_score(thr, theta))
t2 <- as.data.frame(easyRasch2:::sim_partial_score(thr, theta + 0.8))
colnames(t1) <- colnames(t2) <- paste0("I", 1:6)
RMpersonChange(t1, t2)
# A single respondent needs an external calibration
names(thr) <- paste0("I", 1:6)
RMpersonChange(t1[1, ], t2[1, ], item_params = thr)
# Monte Carlo alternative, for comparison
RMpersonChange(t1, t2, critical = "simulate", sim_iter = 200,
parallel = FALSE, seed = 1)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.