rs_characterize: Characterize Response Shift Within Terminal Nodes of a...

View source: R/rs_characterize.R

rs_characterizeR Documentation

Characterize Response Shift Within Terminal Nodes of a Longitudinal GRM Tree

Description

After fitting a longitudinal_grmtree (Phase 1), this function performs Phase 2: post-hoc response shift (RS) characterization within each terminal node. For each subgroup identified by the tree it compares the constrained model (no RS: item parameters equal across time) to an unconstrained model (item parameters free across time) with a likelihood ratio test (LRT); then, only in nodes where the omnibus test survives the across-node adjustment, it tests each item for RS and classifies the type of shift by nested LRTs on the item's parameter sets.

Usage

rs_characterize(
  object,
  node = NULL,
  item_level = TRUE,
  alpha = 0.05,
  p_adjust = "bonferroni",
  global_p_adjust = "bonferroni",
  rs_threshold = 0.3,
  verbose = TRUE,
  ...
)

Arguments

object

A longitudinal_grmtree object fitted by longitudinal_grmtree.

node

Optional integer vector of terminal node IDs to analyze. If NULL (default), all terminal nodes are analyzed.

item_level

Logical. If TRUE (default), perform item-level RS testing. It is performed only for nodes whose omnibus RS is detected after global_p_adjust (i.e. RS_detected == TRUE); nodes that are not significant after adjustment are skipped entirely, so no item rows are produced for them.

alpha

Numeric significance level for RS tests. Default 0.05. Used for the omnibus decision (after global_p_adjust), the item detection decision (after p_adjust), and the component tests that assign the RS type.

p_adjust

Character string specifying the method for adjusting the item detection p-values within each node. Controls the error rate when testing multiple items for RS within a single subgroup. Options: "bonferroni" (default), "holm", "BH" (Benjamini-Hochberg), "BY", "fdr", "hochberg", "hommel", or "none". See p.adjust. FDR is recommended for the exploratory item search.

global_p_adjust

Character string specifying the method for adjusting the omnibus RS p-values across terminal nodes. Controls the family-wise error rate when testing RS in multiple subgroups. Options are the same as p_adjust. Default "bonferroni". The RS_detected column is set from these adjusted p-values, and it is RS_detected that gates item-level testing. Only applied when there are two or more nodes.

rs_threshold

Numeric magnitude threshold on the IRT parameter scale, used only for the descriptive effect-size annotation (RS_magnitude), not for deciding the RS type. Default 0.3. A flagged item is annotated "large" when its larger parameter change (max threshold shift or absolute discrimination change) is at least rs_threshold, and "small" otherwise. The type itself is always determined by the component LRTs (see Details), so the choice of rs_threshold never changes which items are flagged or how they are typed; it only affects the type label when both changes are sub-threshold, and the RS_magnitude annotation.

verbose

Logical. If TRUE (default), print progress messages for each node during processing.

...

Additional arguments passed to mirt during model fitting.

Details

The two-phase framework

Phase 1 (longitudinal_grmtree) embeds a constrained longitudinal GRM (item parameters equal across T1 and T2) in model-based recursive partitioning, identifying subgroups that require different constrained measurement models. Phase 2 (this function) relaxes the equality constraints within each subgroup and asks whether item parameters actually change over time. This separates between-group measurement heterogeneity (captured by the tree) from within-group temporal change (response shift).

Omnibus test and the gate on item-level testing

For each terminal node, a constrained model (all item parameters equal across waves) and an unconstrained model (all free) are fitted and compared by

\chi^2 = -2(\ell_{con} - \ell_{uncon}), \qquad \mathrm{df} = \#\{\text{freed constraints}\}.

The omnibus p-values are then adjusted across nodes (global_p_adjust) and RS_detected is set from the adjusted p-value. Item-level testing is performed only for nodes with RS_detected == TRUE: a node that is not significant after adjustment is skipped, so it contributes no item rows. This is a deliberate two-pass design (all omnibus tests first, then adjustment, then item-level only where warranted) and it guarantees that the item-level results are consistent with the omnibus decision.

Item detection

Within an RS-detected node, each item is first tested for any shift by a joint LRT that frees that item's discrimination and thresholds against the constrained model (df = K: one discrimination plus K-1 thresholds). These joint p-values are adjusted across the items in the node (p_adjust); an item is flagged when its adjusted joint p-value is below alpha. Unflagged items are "None".

Type from the estimated parameter changes (not a confounded LRT)

Once an item is flagged, its type is read from the estimated T1-versus-T2 changes on the IRT (a, b) metric: the absolute discrimination change (discr_diff) indicates reprioritization and the maximum absolute threshold change (thresh_diff) indicates recalibration; both large is Both. A flagged item is always given a real type – if both changes are below rs_threshold it takes the larger one, so a significant item is never left untyped.

This is deliberate. A tempting alternative – decomposing the shift with nested LRTs that free the discrimination or the thresholds in turn – does not work here, because mirt parameterizes the graded model in slope-intercept form where the intercept d = -a\,b. A pure discrimination change (a moves, b constant) therefore forces the intercepts to move, so any LRT that frees the intercepts fires for a reprioritization item, spuriously flagging recalibration. The estimated a and b changes, in contrast, separate the two shift types cleanly (b = -d/a un-confounds them), which is why the type is read from them. Detection remains a likelihood-ratio test; only the attribution of which parameter moved uses the estimated changes, and both are reported (discr_diff, thresh_diff, RS_magnitude) so the classification is fully transparent.

Separating detection (is there a shift? – LRT), type (which parameter moved? – estimated change), and magnitude (how large? – effect size) is the point of the redesign.

Hierarchical error control

Two adjustment layers are applied: global_p_adjust across nodes for "in which subgroups does RS occur?" (default Bonferroni), and p_adjust across items within a node for "which items shift?" (default Bonferroni; FDR recommended for exploration). The component tests that assign the type are a post-hoc decomposition of an already-flagged item and are read at alpha.

Effect sizes

McFadden's pseudo-R^2 = 1 - \ell_{uncon}/\ell_{con} is inherently small in IRT (~0.02) and is best compared across nodes. AIC_{con} - AIC_{uncon} is positive when the unconstrained model is preferred after the parsimony penalty. Item-level discr_diff and thresh_diff give the raw magnitude of the T1-vs-T2 parameter changes.

Value

A list of class "rs_characterization" containing:

global

A data.frame with one row per terminal node and columns:

Node

Terminal node ID.

n

Sample size in the node.

LL_constrained

Log-likelihood of the constrained (no-RS) model.

LL_unconstrained

Log-likelihood of the unconstrained (RS-allowed) model.

LRT_chi2

Omnibus LRT statistic -2(\ell_{con} - \ell_{uncon}).

LRT_df

Degrees of freedom (number of freed constraints).

LRT_p

Raw omnibus p-value.

LRT_p_adj

Omnibus p-value adjusted across nodes (present only when global_p_adjust != "none" and there are two or more nodes).

RS_detected

Logical: whether omnibus RS is detected at alpha after adjustment. This flag gates item-level testing.

pseudo_R2

McFadden's pseudo-R^2, 1 - \ell_{uncon}/\ell_{con}.

AIC_diff

AIC_{con} - AIC_{uncon}; positive favours the unconstrained model.

mu_T2

Latent mean shift at T2 (constrained model).

sigma2_T2

Latent variance at T2.

cor_T1_T2

Test-retest correlation of the latent trait.

converged_constrained, converged_unconstrained

Convergence flags for the two models.

item_level

A data.frame of item-level results, one row per item only for RS-detected nodes (NULL if no node was detected or item_level = FALSE):

Node, Item

Node ID and item number (1..M).

LRT_chi2, LRT_df, LRT_p

The joint item test (free this item's discrimination and thresholds vs the constrained model): statistic, df = K (1 discrimination plus K-1 thresholds), and raw p-value. This is the item detection test.

LRT_p_adj

Joint p-value adjusted across items within the node (p_adjust); an item is flagged when this is below alpha.

RS_type

"Recalibration", "Reprioritization", "Both", or "None" – determined by the component LRTs (see Details), never by a magnitude cut-point.

discr_diff, thresh_diff

Effect sizes: the absolute T1-vs-T2 discrimination change and the maximum absolute threshold change (reported, not used to decide the type).

RS_magnitude

"large"/"small" annotation of a flagged item's effect size against rs_threshold (NA for unflagged items).

parameters

A named list (one element per node) of constrained and unconstrained item-parameter matrices (IRT parameterization).

n_items, alpha, p_adjust, global_p_adjust, rs_threshold

The settings used.

Author(s)

Olayinka Imisioluwa Arimoro olayinka.arimoro@ucalgary.ca, Lisa M. Lix, Tolulope T. Sajobi

References

Oort, F. J. (2005). Using structural equation modeling to detect response shifts and true change. Quality of Life Research, 14(3), 587–598.

Sprangers, M. A. G., & Schwartz, C. E. (1999). Integrating response shift into health-related quality of life research: a theoretical model. Social Science & Medicine, 48(11), 1507–1515.

Benjamini, Y., & Hochberg, Y. (1995). Controlling the false discovery rate: a practical and powerful approach to multiple testing. Journal of the Royal Statistical Society: Series B, 57(1), 289–300.

See Also

longitudinal_grmtree for Phase 1 (tree fitting), print.rs_characterization for the print method, prepare_longitudinal_data for data preparation, p.adjust for p-value adjustment methods

Examples


library(grmtree)
data("grmtree_long_data", package = "grmtree")
items_t1 <- c("MOS_Listen", "MOS_Info", "MOS_Advice_Crisis", "MOS_Confide",
              "MOS_Advice_Want", "MOS_Fears", "MOS_Personal", "MOS_Understand")
ld <- prepare_longitudinal_data(
  data = grmtree_long_data, items_t1 = items_t1,
  items_t2 = paste0(items_t1, "_year1"),
  covariates = c("sex", "age", "residency", "job",
                 "education", "comorbidity_count", "ever_smoker"))
ltree <- longitudinal_grmtree(
  resp_wide ~ sex + age + residency + job +
    education + comorbidity_count + ever_smoker,
  data = ld, n_items = 8, control = grmtree.control(minbucket = 200))

# Default: Bonferroni across nodes and within-node; type from component LRTs
rs <- rs_characterize(ltree)
print(rs)

# FDR for the item search, Bonferroni across nodes
rs <- rs_characterize(ltree, p_adjust = "fdr", global_p_adjust = "bonferroni")

rs$global      # omnibus per node (RS_detected gates the item tests)
rs$item_level  # item detection + type + effect sizes, for detected nodes only


grmtree documentation built on Sept. 2, 2026, 1:07 a.m.