In this tutorial, we’ll run a Rasch model and a LLTM based on the same data as De Boeck and Wilson, Chapter 2.

We’ll use the eRm package for modeling. lme4 is loaded just to get access to a dataset.

library(tidyverse)
library(eRm)
library(lme4) # just to get a dataset

data("VerbAgg")

summary(VerbAgg)
##      Anger    Gender            item           resp            id      
##  Min.   :11   F:5832   S1WantCurse: 316   no     :3973   1      :  24  
##  1st Qu.:17   M:1752   S1WantScold: 316   perhaps:2081   2      :  24  
##  Median :19            S1WantShout: 316   yes    :1530   3      :  24  
##  Mean   :20            S2WantCurse: 316                  4      :  24  
##  3rd Qu.:23            S2WantScold: 316                  5      :  24  
##  Max.   :39            S2WantShout: 316                  6      :  24  
##                        (Other)    :5688                  (Other):7440  
##    btype         situ        mode      r2      
##  curse:2528   other:3792   want:3792   N:3973  
##  scold:2528   self :3792   do  :3792   Y:3611  
##  shout:2528                                    
##                                                
##                                                
##                                                
## 

We’ll need to create a dichotomous version of the response variable to follow along with Ch. 2. We’ll also make the data wide, which is how eRm operates.

#dichotomize for illustrative purposes
VerbAgg <- VerbAgg %>% mutate(respn = case_when(resp == "no" ~ 0,
                                                resp == "perhaps" ~ 1,
                                                resp == "yes" ~ 1))

#make data wide
resp_wide <- VerbAgg %>% select(id, item, respn) %>%
  pivot_wider(names_from = item, values_from = respn)

Basic Rasch Model

Now we can run a Rasch model. This should all be review at this point!

#basic rasch model
RM <- RM(resp_wide[2:25], se = T, sum0 = T)
summary(RM)
## 
## Results of RM estimation: 
## 
## Call:  RM(X = resp_wide[2:25], se = T, sum0 = T) 
## 
## Conditional log-likelihood: -3049.923 
## Number of iterations: 31 
## Number of parameters: 23 
## 
## Item (Category) Difficulty Parameters (eta): with 0.95 CI:
##             Estimate Std. Error lower CI upper CI
## S1WantScold   -0.731      0.131   -0.987   -0.475
## S1WantShout   -0.249      0.128   -0.501    0.003
## S2WantCurse   -1.909      0.153   -2.210   -1.608
## S2WantScold   -0.873      0.132   -1.132   -0.614
## S2WantShout   -0.181      0.128   -0.433    0.070
## S3WantCurse   -0.696      0.130   -0.951   -0.440
## S3WantScold    0.514      0.132    0.254    0.773
## S3WantShout    1.358      0.149    1.065    1.650
## S4wantCurse   -1.245      0.137   -1.514   -0.976
## S4WantScold    0.178      0.129   -0.076    0.432
## S4WantShout    0.871      0.138    0.601    1.141
## S1DoCurse     -1.383      0.140   -1.658   -1.109
## S1DoScold     -0.557      0.129   -0.810   -0.303
## S1DoShout      0.698      0.135    0.434    0.963
## S2DoCurse     -1.037      0.134   -1.300   -0.774
## S2DoScold     -0.113      0.128   -0.365    0.138
## S2DoShout      1.312      0.148    1.022    1.602
## S3DoCurse      0.040      0.129   -0.212    0.293
## S3DoScold      1.335      0.149    1.044    1.626
## S3DoShout      2.871      0.222    2.436    3.306
## S4DoCurse     -0.873      0.132   -1.132   -0.614
## S4DoScold      0.213      0.130   -0.042    0.467
## S4DoShout      1.840      0.165    1.516    2.165
## 
## Item Easiness Parameters (beta) with 0.95 CI:
##                  Estimate Std. Error lower CI upper CI
## beta S1WantCurse    1.383      0.140    1.109    1.658
## beta S1WantScold    0.731      0.131    0.475    0.987
## beta S1WantShout    0.249      0.128   -0.003    0.501
## beta S2WantCurse    1.909      0.153    1.608    2.210
## beta S2WantScold    0.873      0.132    0.614    1.132
## beta S2WantShout    0.181      0.128   -0.070    0.433
## beta S3WantCurse    0.696      0.130    0.440    0.951
## beta S3WantScold   -0.514      0.132   -0.773   -0.254
## beta S3WantShout   -1.358      0.149   -1.650   -1.065
## beta S4wantCurse    1.245      0.137    0.976    1.514
## beta S4WantScold   -0.178      0.129   -0.432    0.076
## beta S4WantShout   -0.871      0.138   -1.141   -0.601
## beta S1DoCurse      1.383      0.140    1.109    1.658
## beta S1DoScold      0.557      0.129    0.303    0.810
## beta S1DoShout     -0.698      0.135   -0.963   -0.434
## beta S2DoCurse      1.037      0.134    0.774    1.300
## beta S2DoScold      0.113      0.128   -0.138    0.365
## beta S2DoShout     -1.312      0.148   -1.602   -1.022
## beta S3DoCurse     -0.040      0.129   -0.293    0.212
## beta S3DoScold     -1.335      0.149   -1.626   -1.044
## beta S3DoShout     -2.871      0.222   -3.306   -2.436
## beta S4DoCurse      0.873      0.132    0.614    1.132
## beta S4DoScold     -0.213      0.130   -0.467    0.042
## beta S4DoShout     -1.840      0.165   -2.165   -1.516
#person parameters
RM.pps <- person.parameter(RM)

#separation reliability
summary(SepRel(RM.pps))
##        Separation Reliability: 0.8821
## 
##             Observed Variance: 2.4882 (Squared Standard Deviation)
## Mean Square Measurement Error: 0.2933 (Model Error Variance)
summary(gofIRT(RM.pps))
## 
## Goodness-of-Fit Tests
##                       value       df p-value
## Collapsed Deviance  588.043      552   0.140
## Hosmer-Lemeshow       7.820        8   0.451
## Rost Deviance      4455.435 16777192   1.000
## Casewise Deviance  7072.594     7322   0.981
## 
## R-Squared Measures
## Pearson R2: 0.366
## Sum-of-Squares R2: 0.366
## McFadden R2: 0.441
## 
## Classifier Results - Confusion Matrix (relative frequencies)
##          observed
## predicted     0     1
##         0 0.412 0.120
##         1 0.114 0.354
## 
## Accuracy: 0.766
## Sensitivity: 0.747
## Specificity: 0.784
## Area under ROC: 0.849
## Gini coefficient: 0.699

Linear Logisitic Test Model (LLTM)

Now for the fun part - we’ll estimate the difficulties associated with characteristics of the items and then compare to our doubly-descriptive Rasch model.

First, we’ll need to create a matrix of item characteristics. eRm needs a matrix of item responses (in this case, the same 0/1 data as used in our basic Rasch model) and a numeric matrix of item characteristics.

Let’s grab our item info first:

q_prep <- select(VerbAgg, item, btype, situ, mode) %>%
  distinct()

What we’ve done here is select just the columns with information about the items, and then saved only the distinct rows (we don’t need all 7,000+ rows of repeated info in the long data).

Now we’ll recode the factors to numeric values, following what De Boeck and Wilson described. We’ll save this as a matrix, which you can think of as a simpler type of data frame. eRm likes matrices, because matrices can be mathematically operated directly on in lots of useful ways.

q_prep <- q_prep %>% mutate(mode = case_when(mode == "do" ~ 1,
                                           mode == "want" ~ 0),
                          situ = case_when(situ == "other" ~ 1,
                                           situ == "self" ~ 0),
                          btype_v_shout = case_when(btype == "curse" ~ 1/2,
                                                    btype == "scold" ~ 1/2,
                                                    btype == "shout" ~ -1),
                          btype_v_scold = case_when(btype == "curse" ~ 1/2,
                                                    btype == "shout" ~ 1/2,
                                                    btype == "scold" ~ -1))

qmat <- select(q_prep, mode, situ, btype_v_shout, btype_v_scold) %>%
  as.matrix()

What we’ve done here is dummy-coded mode and situation, and then done sum coding for behavior type, which has three levels.

Now we can estimate our LLTM:

#Step 2: run LLTM
LLTM <- LLTM(resp_wide[2:25], qmat)
summary(LLTM)
## 
## Results of LLTM estimation: 
## 
## Call:  LLTM(X = resp_wide[2:25], W = qmat) 
## 
## Conditional log-likelihood: -3130.414 
## Number of iterations: 7 
## Number of parameters: 4 
## 
## Basic Parameters eta with 0.95 CI:
##               Estimate Std. Error lower CI upper CI
## mode            -0.671      0.057   -0.783   -0.559
## situ             1.027      0.058    0.913    1.141
## btype_v_shout    1.359      0.050    1.261    1.457
## btype_v_scold    0.701      0.046    0.611    0.792
## 
## Item Easiness Parameters (beta) with 0.95 CI:
##                  Estimate Std. Error lower CI upper CI
## beta S1WantCurse    2.057      0.076    1.908    2.207
## beta S1WantScold    1.005      0.070    0.868    1.142
## beta S1WantShout    0.018      0.067   -0.113    0.150
## beta S2WantCurse    2.057      0.076    1.908    2.207
## beta S2WantScold    1.005      0.070    0.868    1.142
## beta S2WantShout    0.018      0.067   -0.113    0.150
## beta S3WantCurse    1.030      0.042    0.948    1.113
## beta S3WantScold   -0.022      0.039   -0.099    0.055
## beta S3WantShout   -1.009      0.043   -1.092   -0.925
## beta S4wantCurse    1.030      0.042    0.948    1.113
## beta S4WantScold   -0.022      0.039   -0.099    0.055
## beta S4WantShout   -1.009      0.043   -1.092   -0.925
## beta S1DoCurse      1.386      0.090    1.209    1.563
## beta S1DoScold      0.334      0.088    0.162    0.506
## beta S1DoShout     -0.653      0.088   -0.825   -0.480
## beta S2DoCurse      1.386      0.090    1.209    1.563
## beta S2DoScold      0.334      0.088    0.162    0.506
## beta S2DoShout     -0.653      0.088   -0.825   -0.480
## beta S3DoCurse      0.359      0.068    0.227    0.492
## beta S3DoScold     -0.693      0.069   -0.829   -0.557
## beta S3DoShout     -1.680      0.074   -1.825   -1.534
## beta S4DoCurse      0.359      0.068    0.227    0.492
## beta S4DoScold     -0.693      0.069   -0.829   -0.557
## beta S4DoShout     -1.680      0.074   -1.825   -1.534
## check the effects of item features
LLTM$etapar*-1
##          mode          situ btype_v_shout btype_v_scold 
##     0.6712050    -1.0269967    -1.3592355    -0.7014138

Out output is identical to what De Boeck and Wilson reported:

In the output above, item difficulties (well, easiness) are calculated by summing up the effects of item characteristics. We can compare these values to the Rasch model estimates.

#Step 3: Compared to basic RM
##correlation and r2
cor(RM$betapar*-1, LLTM$betapar*-1)
## [1] 0.9418711
cor(RM$betapar*-1, LLTM$betapar*-1)^2
## [1] 0.8871211

So uh, yeah, this is a pretty solid accounting of what makes these aggression items easy/difficult to endorse.

A graph:

ggplot(data = NULL, aes(LLTM$betapar*-1, y = RM$betapar*-1))+
  geom_abline(slope = 1, intercept = 0)+
  geom_smooth(method = "lm")+
  geom_point()+
  labs(x = "LLTM Item Difficulty", y = "Rasch Item Difficulty")+
  theme_bw()
## `geom_smooth()` using formula 'y ~ x'