Provides methods for recursive partitioning based on the
'Graded Response Model' ('GRM'), extending the 'MOB' algorithm from the
'partykit' package. The package allows for fitting
'GRM' trees that partition the population into homogeneous
subgroups based on item response patterns and covariates.
Includes specialized plotting functions for visualizing 'GRM' trees
with different terminal node displays (threshold regions,
parameter profiles, and factor score distributions). The package also implements the Longitudinal GRMTree for detecting response shift in PROMs measured at two time points, embedding a constrained two-factor longitudinal GRM within recursive partitioning, with post-hoc characterization of recalibration and reprioritization. Random-forest ensembles (`grmforest()`) with permutation variable importance are available for both the cross-sectional and longitudinal trees.
For more details on the methods, see Samejima (1969)
The grmtree package implements advanced tree-based recursive partitioning methods for Graded Response Models (GRM), providing a powerful framework for detecting and analyzing differential item functioning (DIF) in polytomous items from patient-reported outcome measures (PROMs) and other psychological assessments. DIF occurs when individuals with the same underlying latent trait (e.g., health status, quality of life, or psychological attribute) respond differently to assessment items based on extraneous characteristics such as age, gender, education level, or clinical subgroups. This measurement bias can compromise the validity and fairness of assessments across diverse populations.
The GRMTree methodology combines the psychometric rigor of item response theory with the interpretability of decision trees to:
The package also implements the Longitudinal GRMTree for detecting response shift in PROMs measured at two time points, embedding a constrained two-factor longitudinal GRM within recursive partitioning and characterizing recalibration and reprioritization within data-driven subgroups.
mirt package for GRM estimation and the partykit ecosystem for tree visualizationThis package is particularly valuable for researchers, psychometricians, and health outcomes specialists who require robust methods for ensuring measurement invariance and equity in their assessment instruments across diverse populations.
Install from CRAN (when available):
install.packages("grmtree")
Install the development version from GitHub
# Install devtools if not already installed
install.packages("devtools")
# Install the grmtree
devtools::install_github("Predicare1/grmtree")
# Install with vignettes (takes longer but includes vignettes)
devtools::install_github("Predicare1/grmtree", build_vignettes = TRUE)
# Load the package
library(grmtree)
library(dplyr)
# Load the data
data("grmtree_data") # Sample dataset included with package
# Prepare the data
resp.data <- grmtree_data %>%
mutate_at(vars(starts_with("MOS")), as.ordered) %>%
mutate_at(vars(c(sex, Education)), as.factor)
# Create response as outcomes
resp.data$resp <- data.matrix(resp.data[, 1:8])
## GRMTree control parameters with Benjamini-Hochberg
grm_control <- grmtree.control(
minbucket = 350,
p_adjust = "BH", alpha = 0.05)
# Fit a GRM tree
tree <- grmtree(resp ~ sex + age + Education,
data = resp.data,
control = grm_control)
# Print the GRMTree model
print(tree)
# Visualize the tree
plot(tree) # Default regions plot
plot(tree, type = "profile") # Parameter profiles
plot(tree, type = "histogram") # Factor score distributions
# Extract parameters
threshpar_grmtree(tree) # Threshold parameters
discrpar_grmtree(tree) # Discrimination parameters
The Longitudinal GRMTree detects response shift in PROMs measured at two time points, using a two-phase approach: Phase 1 identifies patient subgroups whose longitudinal measurement model differs, and Phase 2 tests for response shift within each subgroup and classifies the affected items.
# Load the synthetic longitudinal dataset
data("grmtree_long_data")
# Prepare the wide-format response matrix
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")
)
# Phase 1: fit the tree to identify subgroups
tree <- longitudinal_grmtree(
resp_wide ~ sex + age + residency + job +
education + comorbidity_count + ever_smoker,
data = ld, n_items = 8,
control = grmtree.control(minbucket = 200)
)
print(tree)
# Phase 2: characterize response shift within each subgroup
rs <- rs_characterize(tree, p_adjust = "fdr", global_p_adjust = "bonferroni")
print(rs)
# Visualize response shift
plot_rs_tree(tree, rs)
plot_rs_heatmap(rs)
Detailed interactive tutorials are available:
browseVignettes("grmtree")
# Fit a forest with 50 trees
forest <- grmforest(resp ~ sex + age + Education,
data = resp.data,
control = grmforest.control(control = grm_control,
n_tree = 50,
n_cores = 2))
# Variable importance
vim <- varimp(forest)
print(vim)
plot(vim)
# Examine individual trees
plot(forest$trees[[1]]) # First tree
The same forest engine screens many covariates for a longitudinal tree — just
pass tree_fun = longitudinal_grmtree:
forest <- grmforest(
resp_wide ~ sex + age + residency + job +
education + comorbidity_count + ever_smoker,
data = ld,
control = grmforest.control(n_tree = 50, n_cores = 2,
control = grmtree.control(minbucket = 200)),
tree_fun = longitudinal_grmtree,
tree_args = list(n_items = 8)
)
varimp(forest)
Olayinka Imisioluwa Arimoro (olayinka.arimoro@ucalgary.ca{.email}), Lisa M. Lix, Tolulope T. Sajobi
Contributions are welcome! Please submit issues and pull requests via GitHub: https://github.com/Predicare1/grmtree/issues