The grmtree package implements recursive partitioning
for Graded Response Models (GRM), allowing researchers to test for
differential item functioning (DIF) and identify heterogeneous subgroups
in their data based on item response patterns and covariates. This
vignette describes the implementation of the tree-based graded response
model (GRMTree) to test for DIF on the sample Medical Outcomes Study
Social Support Survey (MOS-SS). This vignette demonstrates:
Data preparation and exploration
Unidimensionality checking
GRM fitting
GRMTree construction and interpretation
To implement the tree-based GRM (GRMTree), you will install the following packages if not previously installed.
Once installed, load the packages as follows:
The data set used in this demonstration is a test/sample data for the package.
Now, let’s load this tidy data set into R.
## Load the data
data("grmtree_data", package = "grmtree")
## Take a glimpse at the data
glimpse(grmtree_data)
#> Rows: 3,500
#> Columns: 17
#> $ MOS_Listen <chr> "5", "4", "5", "3", "5", "2", "5", "5", "2", "3", "3…
#> $ MOS_Info <chr> "5", "3", "5", "3", "5", "3", "5", "5", "2", "4", "3…
#> $ MOS_Advice_Crisis <chr> "5", "3", "5", "3", "5", "5", "5", "5", "4", "4", "3…
#> $ MOS_Confide <chr> "5", "4", "4", "2", "4", "4", "5", "5", "2", "3", "3…
#> $ MOS_Advice_Want <chr> "5", "2", "4", "3", "4", "3", "5", "5", "4", "3", "3…
#> $ MOS_Fears <chr> "5", "2", "5", "4", "5", "4", "5", "5", "1", "2", "1…
#> $ MOS_Personal <chr> "5", "2", "5", "1", "5", "2", "5", "5", "4", "2", "3…
#> $ MOS_Understand <chr> "5", "2", "5", "1", "4", "3", "5", "5", "4", "2", "3…
#> $ sex <chr> "Male", "Male", "Male", "Male", "Male", "Female", "M…
#> $ age <dbl> 69, 66, 72, 52, 61, 57, 61, 71, 77, 65, 55, 64, 45, …
#> $ residency <chr> "urban", "urban", "urban", "urban", "urban", "rural"…
#> $ depressed <chr> "No", "No", "No", "Yes", "No", "No", "Yes", "No", "N…
#> $ bmi <dbl> 22.85714, 33.59375, 24.38272, 31.14187, 25.88057, 24…
#> $ Education <chr> "Primary/High school", "College/University", "Colleg…
#> $ job <chr> "Unemployed", "Unemployed", "Unemployed", "Unemploye…
#> $ smoker <chr> "No", "No", "Yes", "No", "No", "No", "Yes", "Yes", "…
#> $ multimorbidity <chr> "2+", "2+", "1", "1", "2+", "2+", "2+", "1", "2+", "…There are various ways to check for the unidimensionality assumption. Some including using exploratory factor analysis (through parallel analysis), scree plot of the eigen values, and contrasts from principal component analysis.
Here, we will use the scree plot of eigen values. Reeve, et al. suggested that a ratio of first-to-second eigenvalues greater than four is evidence of unidimensionality.
## Create the response data (the 8 MOS-SS items)
response_data <- grmtree_data %>%
dplyr::select(MOS_Listen:MOS_Understand) %>%
mutate_at(vars(starts_with("MOS")), as.ordered)
## Create response as outcomes
response_data$resp <- data.matrix(response_data[, 1:8])## Calculate the polychoric correlation of items
polycorr_mos <- polychoric(response_data$resp, global=FALSE)$rho
## Return the eigen values
polycorr_eigen_mos <- eigen(polycorr_mos)$values
round(polycorr_eigen_mos, 3)
## Ratio of first and second eigen value
mos_ratio <- round(round(polycorr_eigen_mos, 3)[1]/round(polycorr_eigen_mos, 3)[2],3)
## Print the result
mos_ratio
cat("The ratio of the first-to-second eigen value is", mos_ratio,
"which is >4 suggesting that the unidimensionality assumption is satisfied", "\n")Now, let’s create the screen plot.
## Scree plot of eigen values
plot(1:length(polycorr_eigen_mos), polycorr_eigen_mos,
type = "b", pch = 20, xlab = "", ylab = "Eigen values")Note: The type = "b" argument means we
desire that the plot creates both points and lines,
Based on the scree plot, we assume that the MOS-SS emotional domain is unidimensional. This implies that one dominant latent trait is being measured and that this trait is the driving force for the responses observed for each item in the measure.
Other ways to check for unidimensionality of the MOS-SS emotional domain are shown below
## Perform EFA with 1 factors
efa_mos <- fa(response_data$resp, nfactors = 1, rotate = "varimax", fm = "mle")
## Print the results
summary(efa_mos)
print(efa_mos, sort=TRUE)
efa_mos$loadings
## Visualizing factor structure using fa.diagram
fa.diagram(efa_mos, main = "EFA Factor Structure")
## Scree plot to visualize the number of factors
fa.parallel(response_data$resp, fa = "fa")Having established unidimensionality, let’s create the GRM.
## Create GRM
mos_grm <- mirt(data = response_data$resp,
model = 1,
itemtype = "graded", SE = TRUE, method = "EM",
verbose = FALSE)Note: The argument model = 1 means that
default is 1, indicating that a unidimensional model will be fitted
## Get the coefficients
mos_coef <- coef(mos_grm, IRTpars = T, simplify = TRUE)
mos_coef
#> $items
#> a b1 b2 b3 b4
#> MOS_Listen 3.815 -2.012 -1.400 -0.805 0.168
#> MOS_Info 3.140 -2.057 -1.333 -0.535 0.658
#> MOS_Advice_Crisis 3.647 -1.875 -1.186 -0.474 0.639
#> MOS_Confide 5.352 -1.697 -1.137 -0.562 0.281
#> MOS_Advice_Want 4.000 -1.660 -1.079 -0.386 0.559
#> MOS_Fears 4.508 -1.431 -0.961 -0.447 0.340
#> MOS_Personal 5.690 -1.519 -1.000 -0.401 0.461
#> MOS_Understand 4.915 -1.644 -1.085 -0.457 0.458
#>
#> $means
#> F1
#> 0
#>
#> $cov
#> F1
#> F1 1
## Get the residuals
residuals(mos_grm, type = "Q3")
#> Q3 summary statistics:
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> -0.334 -0.235 -0.152 -0.122 -0.064 0.358
#>
#> MOS_Listen MOS_Info MOS_Advice_Crisis MOS_Confide
#> MOS_Listen 1.000 0.049 -0.071 0.163
#> MOS_Info 0.049 1.000 0.358 -0.129
#> MOS_Advice_Crisis -0.071 0.358 1.000 -0.186
#> MOS_Confide 0.163 -0.129 -0.186 1.000
#> MOS_Advice_Want -0.186 -0.052 0.049 -0.190
#> MOS_Fears -0.129 -0.298 -0.310 -0.068
#> MOS_Personal -0.301 -0.241 -0.250 -0.334
#> MOS_Understand -0.233 -0.163 -0.193 -0.273
#> MOS_Advice_Want MOS_Fears MOS_Personal MOS_Understand
#> MOS_Listen -0.186 -0.129 -0.301 -0.233
#> MOS_Info -0.052 -0.298 -0.241 -0.163
#> MOS_Advice_Crisis 0.049 -0.310 -0.250 -0.193
#> MOS_Confide -0.190 -0.068 -0.334 -0.273
#> MOS_Advice_Want 1.000 -0.116 -0.161 -0.089
#> MOS_Fears -0.116 1.000 0.062 -0.144
#> MOS_Personal -0.161 0.062 1.000 0.015
#> MOS_Understand -0.089 -0.144 0.015 1.000
## Compute the M2 model fit statistic
M2(mos_grm, type = "C2")
#> M2 df p RMSEA RMSEA_5 RMSEA_95 SRMSR TLI CFI
#> stats 1568.994 20 0 0.1487777 0.1425678 0.1550398 0.0391844 0.961774 0.9726957
## Infit and outfit statistics
mirt::itemfit(mos_grm, c('S_X2', 'infit'), method = 'EAP')
#> item outfit z.outfit infit z.infit S_X2 df.S_X2 RMSEA.S_X2
#> 1 MOS_Listen 0.835 -1.612 0.950 -1.526 248.617 59 0.030
#> 2 MOS_Info 0.891 -2.890 0.996 -0.108 162.253 62 0.021
#> 3 MOS_Advice_Crisis 0.851 -3.504 0.976 -0.770 171.474 59 0.023
#> 4 MOS_Confide 0.692 -3.506 0.871 -4.157 133.765 48 0.023
#> 5 MOS_Advice_Want 0.886 -2.036 0.984 -0.527 238.147 58 0.030
#> 6 MOS_Fears 0.917 -0.679 0.942 -1.794 214.704 57 0.028
#> 7 MOS_Personal 0.680 -2.855 0.891 -3.538 176.772 48 0.028
#> 8 MOS_Understand 0.747 -2.740 0.914 -2.782 177.138 51 0.027
#> p.S_X2
#> 1 0
#> 2 0
#> 3 0
#> 4 0
#> 5 0
#> 6 0
#> 7 0
#> 8 0
## Could also use method = 'ML'Based on multiple fit indices including the Tucker–Lewis index (TLI) and Comparative fit index (CFI), we conclude that GRM has a good fit to the data.
Now, let’s create the GRNTree using covariates to test for DIF. To implement the GRMTree, it follows this four-step process.
GRMTree implementation process showing the four-step recursive partitioning approach for detecting differential item functioning
Before we proceed, let’s put the variables in their proper formats:
age
and BMI will be converted to factor since they are
categorical variables and the MOS-SS emotional domain items will be
converted to ordinal variables as required for the GRMTree.
## Prepare the data
resp.data <- grmtree_data %>%
mutate_at(vars(starts_with("MOS")), as.ordered) %>%
mutate_at(vars(c(sex, residency, depressed,
Education, job, smoker,
multimorbidity)), as.factor)
## Explore the data
head(resp.data)
#> # A tibble: 6 × 17
#> MOS_Listen MOS_Info MOS_Advice_Crisis MOS_Confide MOS_Advice_Want MOS_Fears
#> <ord> <ord> <ord> <ord> <ord> <ord>
#> 1 5 5 5 5 5 5
#> 2 4 3 3 4 2 2
#> 3 5 5 5 4 4 5
#> 4 3 3 3 2 3 4
#> 5 5 5 5 4 4 5
#> 6 2 3 5 4 3 4
#> # ℹ 11 more variables: MOS_Personal <ord>, MOS_Understand <ord>, sex <fct>,
#> # age <dbl>, residency <fct>, depressed <fct>, bmi <dbl>, Education <fct>,
#> # job <fct>, smoker <fct>, multimorbidity <fct>
## Check the structure of the data
glimpse(resp.data)
#> Rows: 3,500
#> Columns: 17
#> $ MOS_Listen <ord> 5, 4, 5, 3, 5, 2, 5, 5, 2, 3, 3, 4, 5, 2, 5, 3, 5, 4…
#> $ MOS_Info <ord> 5, 3, 5, 3, 5, 3, 5, 5, 2, 4, 3, 4, 5, 2, 4, 4, 4, 3…
#> $ MOS_Advice_Crisis <ord> 5, 3, 5, 3, 5, 5, 5, 5, 4, 4, 3, 4, 2, 2, 4, 4, 4, 3…
#> $ MOS_Confide <ord> 5, 4, 4, 2, 4, 4, 5, 5, 2, 3, 3, 4, 5, 2, 5, 4, 5, 3…
#> $ MOS_Advice_Want <ord> 5, 2, 4, 3, 4, 3, 5, 5, 4, 3, 3, 4, 2, 2, 5, 4, 4, 2…
#> $ MOS_Fears <ord> 5, 2, 5, 4, 5, 4, 5, 5, 1, 2, 1, 4, 5, 2, 5, 4, 4, 4…
#> $ MOS_Personal <ord> 5, 2, 5, 1, 5, 2, 5, 5, 4, 2, 3, 4, 5, 2, 5, 4, 4, 3…
#> $ MOS_Understand <ord> 5, 2, 5, 1, 4, 3, 5, 5, 4, 2, 3, 4, 5, 2, 5, 4, 4, 3…
#> $ sex <fct> Male, Male, Male, Male, Male, Female, Male, Female, …
#> $ age <dbl> 69, 66, 72, 52, 61, 57, 61, 71, 77, 65, 55, 64, 45, …
#> $ residency <fct> urban, urban, urban, urban, urban, rural, urban, urb…
#> $ depressed <fct> No, No, No, Yes, No, No, Yes, No, No, No, Yes, No, N…
#> $ bmi <dbl> 22.85714, 33.59375, 24.38272, 31.14187, 25.88057, 24…
#> $ Education <fct> Primary/High school, College/University, College/Uni…
#> $ job <fct> Unemployed, Unemployed, Unemployed, Unemployed, Unem…
#> $ smoker <fct> No, No, Yes, No, No, No, Yes, Yes, No, No, No, Yes, …
#> $ multimorbidity <fct> 2+, 2+, 1, 1, 2+, 2+, 2+, 1, 2+, 2+, 2+, 2+, 1, 2+, …
## 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 the GRMTree model
mos_grmtree <- grmtree(resp ~ sex + age + bmi + Education + depressed +
residency + job + multimorbidity + smoker,
data = resp.data,
control = grm_control)Note: Unlike previous tree-based item response
theory models, currently, the grmtree package implemented
other post-hoc multiple adjustments methods and also the Bonferroni
correction. The implemented post-hoc multiple adjustments methods
include, “bonferroni” (Bonferroni), “holm” (Holm-Bonferroni), “BH”
(Benjamini-Hochberg), “BY” (Benjamini-Yekutieli), “hochberg” (Hochberg),
and “hommel” (Hommel).
See ?grmtree and ?grmtree.control for more
information on other control arguments. Also see below an example of
using other multiple comparison methods with the control parameters in
the function.
## Bonferroni correction
tree_bonf <- grmtree(response ~ covariate1 + covariate2, data = df,
control = grmtree.control(p_adjust = "bonferroni"))
## Hommel
tree_bh <- grmtree(response ~ covariate1 + covariate2, data = df,
control = grmtree.control(p_adjust = "hommel"))
## Holm-Bonferroni
tree_holm <- grmtree(response ~ covariate1 + covariate2, data = df,
control = grmtree.control(p_adjust = "holm"))We can print the tree using the print() function. Note
that using print(mos_grmtree) will print the tree with the
item parameters. The code below also includes a way to print a
simplified version of the tree showing only the nodes.
## Print the tree model
print(mos_grmtree)
#> Graded Response Model Tree
#>
#> Model formula:
#> resp ~ sex + age + bmi + Education + depressed + residency +
#> job + multimorbidity + smoker
#>
#> Fitted party:
#> [1] root
#> | [2] age <= 69
#> | | [3] sex in Female: n = 371
#> | | $items
#> | | a b1 b2 b3 b4
#> | | respMOS_Listen 3.327 -2.309 -1.466 -0.792 0.389
#> | | respMOS_Info 3.172 -1.920 -1.146 -0.446 0.891
#> | | respMOS_Advice_Crisis 3.714 -1.701 -1.029 -0.444 0.865
#> | | respMOS_Confide 4.595 -1.775 -1.259 -0.651 0.458
#> | | respMOS_Advice_Want 4.130 -1.566 -1.057 -0.409 0.606
#> | | respMOS_Fears 4.601 -1.378 -0.868 -0.450 0.531
#> | | respMOS_Personal 5.513 -1.539 -0.972 -0.374 0.666
#> | | respMOS_Understand 4.084 -1.551 -1.007 -0.337 0.662
#> | |
#> | | $means
#> | | F1
#> | | 0
#> | |
#> | | $cov
#> | | F1
#> | | F1 1
#> | |
#> | | [4] sex in Male: n = 1919
#> | | $items
#> | | a b1 b2 b3 b4
#> | | respMOS_Listen 3.663 -2.040 -1.389 -0.854 0.106
#> | | respMOS_Info 2.868 -2.183 -1.386 -0.553 0.697
#> | | respMOS_Advice_Crisis 3.443 -1.889 -1.215 -0.459 0.675
#> | | respMOS_Confide 5.416 -1.716 -1.118 -0.559 0.260
#> | | respMOS_Advice_Want 4.024 -1.654 -1.070 -0.391 0.580
#> | | respMOS_Fears 4.480 -1.422 -0.953 -0.448 0.327
#> | | respMOS_Personal 5.805 -1.507 -0.969 -0.398 0.468
#> | | respMOS_Understand 5.096 -1.625 -1.036 -0.434 0.474
#> | |
#> | | $means
#> | | F1
#> | | 0
#> | |
#> | | $cov
#> | | F1
#> | | F1 1
#> | |
#> | [5] age > 69: n = 1210
#> | $items
#> | a b1 b2 b3 b4
#> | respMOS_Listen 4.361 -1.896 -1.397 -0.740 0.205
#> | respMOS_Info 3.657 -1.923 -1.322 -0.540 0.540
#> | respMOS_Advice_Crisis 3.999 -1.923 -1.197 -0.507 0.525
#> | respMOS_Confide 5.674 -1.645 -1.129 -0.539 0.266
#> | respMOS_Advice_Want 3.947 -1.704 -1.099 -0.371 0.511
#> | respMOS_Fears 4.514 -1.466 -1.005 -0.443 0.307
#> | respMOS_Personal 5.604 -1.534 -1.056 -0.412 0.389
#> | respMOS_Understand 5.054 -1.712 -1.183 -0.526 0.374
#> |
#> | $means
#> | F1
#> | 0
#> |
#> | $cov
#> | F1
#> | F1 1
#> |
#>
#> Number of inner nodes: 2
#> Number of terminal nodes: 3
#> Number of parameters per node: 3
#> Objective function (negative log-likelihood): 25186.57
print(mos_grmtree, FUN = function(x) " *")
#> Graded Response Model Tree
#>
#> Model formula:
#> resp ~ sex + age + bmi + Education + depressed + residency +
#> job + multimorbidity + smoker
#>
#> Fitted party:
#> [1] root
#> | [2] age <= 69
#> | | [3] sex in Female *
#> | | [4] sex in Male *
#> | [5] age > 69 *
#>
#> Number of inner nodes: 2
#> Number of terminal nodes: 3
#> Number of parameters per node: 3
#> Objective function (negative log-likelihood): 25186.57Now, we can plot the tree using the plot() function. We
have implemented several plotting options including plot the
distribution of the factor scores in each node overlayed by a normal
curve. See ?plot for options of plots available.
## Create the histogram plot of the factor scores
plot(mos_grmtree, type = "histogram", tnex = 2L)
#> Processing node: 3
#> Processing node: 4
#> Processing node: 5
## Create the profile plot with different options
plot(mos_grmtree, type = "profile", tnex = 2L, what = "threshold")Note: The tnex = 2L argument is a
numeric value giving the terminal node extension in relation to the
inner nodes.
You may also rename a covariate in the plot. Let’s assume we want to
rename the variable that splits at the root node from age
to Age.
## Return the names of the covariates to know the position of age
names(mos_grmtree$data)
#> [1] "resp" "sex" "age" "bmi"
#> [5] "Education" "depressed" "residency" "job"
#> [9] "multimorbidity" "smoker"
## Rename the age to Age (Uncomment the code below and change to the correct name)
#names(mos_grmtree$data)[3] <- "Age"
## Create the regions plot (by default)
plot(mos_grmtree)
More than one subgroup (terminal node) was identified, suggesting the
presence of sample heterogeneity with respect to DIF on the MOS-SS
emotional domain items. Specifically, the GRMTree identified three
distinct subgroups defined by interactions among age, sex and smoking
status as splitting variables. Subgroup 1 consists of female patients
who are ≤69 years old, subgroup 2 consists of males who are ≤69 years,
and subgroup 3 consists of patients who are > 69 years. In the figure
above, the larger the sections of the bars for each response category,
the more likely patients are to endorse that category. For a more
detailed example on the interpretation of these types of plot, see the
article below.
## Extract and print the threshold parameters
thresholds <- threshpar_grmtree(mos_grmtree)
print(thresholds)
#> Node Item b1 b2 b3 b4
#> 1 3 respMOS_Listen -2.308581 -1.4656879 -0.7924741 0.3891970
#> 2 3 respMOS_Info -1.920238 -1.1458453 -0.4455881 0.8912573
#> 3 3 respMOS_Advice_Crisis -1.700618 -1.0292038 -0.4444648 0.8650516
#> 4 3 respMOS_Confide -1.774537 -1.2588305 -0.6510803 0.4584325
#> 5 3 respMOS_Advice_Want -1.566310 -1.0568062 -0.4091240 0.6060837
#> 6 3 respMOS_Fears -1.377683 -0.8681593 -0.4503415 0.5313636
#> 7 3 respMOS_Personal -1.538954 -0.9723585 -0.3744289 0.6658615
#> 8 3 respMOS_Understand -1.551128 -1.0068864 -0.3367904 0.6619284
#> 9 4 respMOS_Listen -2.040280 -1.3890196 -0.8544978 0.1057268
#> 10 4 respMOS_Info -2.183446 -1.3856741 -0.5527815 0.6969514
#> 11 4 respMOS_Advice_Crisis -1.889219 -1.2148736 -0.4590243 0.6753132
#> 12 4 respMOS_Confide -1.715802 -1.1176107 -0.5585143 0.2596022
#> 13 4 respMOS_Advice_Want -1.654020 -1.0700153 -0.3908090 0.5801000
#> 14 4 respMOS_Fears -1.421533 -0.9528592 -0.4478088 0.3268731
#> 15 4 respMOS_Personal -1.507029 -0.9686785 -0.3980860 0.4683781
#> 16 4 respMOS_Understand -1.625419 -1.0364005 -0.4343498 0.4736214
#> 17 5 respMOS_Listen -1.896189 -1.3971894 -0.7398447 0.2051288
#> 18 5 respMOS_Info -1.923081 -1.3221471 -0.5396625 0.5395678
#> 19 5 respMOS_Advice_Crisis -1.922918 -1.1967558 -0.5068723 0.5249993
#> 20 5 respMOS_Confide -1.645498 -1.1292589 -0.5388327 0.2656753
#> 21 5 respMOS_Advice_Want -1.703551 -1.0992689 -0.3705977 0.5110057
#> 22 5 respMOS_Fears -1.466102 -1.0048158 -0.4430565 0.3071656
#> 23 5 respMOS_Personal -1.533905 -1.0556259 -0.4122411 0.3888965
#> 24 5 respMOS_Understand -1.711838 -1.1829442 -0.5260505 0.3743661
## Extract and print the discrimination parameters
discriminations <- discrpar_grmtree(mos_grmtree)
print(discriminations)
#> Node Item Discrimination
#> 1 3 respMOS_Listen 3.327051
#> 2 3 respMOS_Info 3.171943
#> 3 3 respMOS_Advice_Crisis 3.714370
#> 4 3 respMOS_Confide 4.595353
#> 5 3 respMOS_Advice_Want 4.129881
#> 6 3 respMOS_Fears 4.600672
#> 7 3 respMOS_Personal 5.513398
#> 8 3 respMOS_Understand 4.084293
#> 9 4 respMOS_Listen 3.663307
#> 10 4 respMOS_Info 2.868277
#> 11 4 respMOS_Advice_Crisis 3.443248
#> 12 4 respMOS_Confide 5.415794
#> 13 4 respMOS_Advice_Want 4.024122
#> 14 4 respMOS_Fears 4.479991
#> 15 4 respMOS_Personal 5.804789
#> 16 4 respMOS_Understand 5.096428
#> 17 5 respMOS_Listen 4.361493
#> 18 5 respMOS_Info 3.656771
#> 19 5 respMOS_Advice_Crisis 3.998893
#> 20 5 respMOS_Confide 5.673946
#> 21 5 respMOS_Advice_Want 3.946687
#> 22 5 respMOS_Fears 4.514427
#> 23 5 respMOS_Personal 5.603528
#> 24 5 respMOS_Understand 5.053900
## Extract and print the item parameters
itemspars <- itempar_grmtree(mos_grmtree)
print(itemspars)
#> Node Item Discrimination AvgThreshold
#> 1 3 respMOS_Listen 3.327051 -1.0443865
#> 2 3 respMOS_Info 3.171943 -0.6551036
#> 3 3 respMOS_Advice_Crisis 3.714370 -0.5773087
#> 4 3 respMOS_Confide 4.595353 -0.8065038
#> 5 3 respMOS_Advice_Want 4.129881 -0.6065391
#> 6 3 respMOS_Fears 4.600672 -0.5412052
#> 7 3 respMOS_Personal 5.513398 -0.5549699
#> 8 3 respMOS_Understand 4.084293 -0.5582190
#> 9 4 respMOS_Listen 3.663307 -1.0445177
#> 10 4 respMOS_Info 2.868277 -0.8562376
#> 11 4 respMOS_Advice_Crisis 3.443248 -0.7219508
#> 12 4 respMOS_Confide 5.415794 -0.7830813
#> 13 4 respMOS_Advice_Want 4.024122 -0.6336862
#> 14 4 respMOS_Fears 4.479991 -0.6238320
#> 15 4 respMOS_Personal 5.804789 -0.6013538
#> 16 4 respMOS_Understand 5.096428 -0.6556369
#> 17 5 respMOS_Listen 4.361493 -0.9570236
#> 18 5 respMOS_Info 3.656771 -0.8113308
#> 19 5 respMOS_Advice_Crisis 3.998893 -0.7753867
#> 20 5 respMOS_Confide 5.673946 -0.7619786
#> 21 5 respMOS_Advice_Want 3.946687 -0.6656029
#> 22 5 respMOS_Fears 4.514427 -0.6517023
#> 23 5 respMOS_Personal 5.603528 -0.6532189
#> 24 5 respMOS_Understand 5.053900 -0.7616168
#> Thresholds
#> 1 -2.3085809, -1.4656879, -0.7924741, 0.3891970
#> 2 -1.9202380, -1.1458453, -0.4455881, 0.8912573
#> 3 -1.7006177, -1.0292038, -0.4444648, 0.8650516
#> 4 -1.7745371, -1.2588305, -0.6510803, 0.4584325
#> 5 -1.5663100, -1.0568062, -0.4091240, 0.6060837
#> 6 -1.3776834, -0.8681593, -0.4503415, 0.5313636
#> 7 -1.5389536, -0.9723585, -0.3744289, 0.6658615
#> 8 -1.5511276, -1.0068864, -0.3367904, 0.6619284
#> 9 -2.0402800, -1.3890196, -0.8544978, 0.1057268
#> 10 -2.1834461, -1.3856741, -0.5527815, 0.6969514
#> 11 -1.8892186, -1.2148736, -0.4590243, 0.6753132
#> 12 -1.7158023, -1.1176107, -0.5585143, 0.2596022
#> 13 -1.654020, -1.070015, -0.390809, 0.580100
#> 14 -1.4215330, -0.9528592, -0.4478088, 0.3268731
#> 15 -1.5070286, -0.9686785, -0.3980860, 0.4683781
#> 16 -1.6254187, -1.0364005, -0.4343498, 0.4736214
#> 17 -1.8961890, -1.3971894, -0.7398447, 0.2051288
#> 18 -1.9230815, -1.3221471, -0.5396625, 0.5395678
#> 19 -1.9229181, -1.1967558, -0.5068723, 0.5249993
#> 20 -1.6454980, -1.1292589, -0.5388327, 0.2656753
#> 21 -1.7035508, -1.0992689, -0.3705977, 0.5110057
#> 22 -1.4661024, -1.0048158, -0.4430565, 0.3071656
#> 23 -1.5339051, -1.0556259, -0.4122411, 0.3888965
#> 24 -1.7118384, -1.1829442, -0.5260505, 0.3743661Note: The itempar_grmtree extracts both
discrimination parameters and average threshold parameters for each item
from all terminal nodes of a graded response model tree. See
?itempar_grmtree for more information.
This vignette demonstrated basic usage of grmtree for
identifying DIF in polytomous items. Key steps included checking
dimensionality, fitting the GRM, and interpreting the resulting
tree.