library(knitr)
library(cacIRT)
library(here)
## Warning: package 'here' was built under R version 4.3.3
## here() starts at C:/Users/sgunter/OneDrive - NCCER/Projects/ANSI Accreditation/2024
library(readxl)
library(mirt)
## Loading required package: stats4
## Loading required package: lattice
library(tidyverse)
## Warning: package 'lubridate' was built under R version 4.3.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.2     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.2     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
knitr::opts_chunk$set(echo = TRUE, include = TRUE)
# Load the data
path <- here("BoomTruck")
cacData <- read_excel("BoomTruck/BoomTruck_Form1-responsedata.xlsx")

# remove column 1 through 11
cacData <- cacData[, -c(1:11)]
# Calibrate the items with a 2PL IRT model. This is actually not needed with the pnr() method below because it's non-parametric. IRT calibration was initially performed for other approaches such as Lee and Rudner. 
cacIRTModel <- mirt(cacData, 1, itemtype = '2PL')
## 
Iteration: 1, Log-Lik: -15926.866, Max-Change: 2.69625
Iteration: 2, Log-Lik: -15635.069, Max-Change: 1.10774
Iteration: 3, Log-Lik: -15604.358, Max-Change: 0.27463
Iteration: 4, Log-Lik: -15599.670, Max-Change: 0.11966
Iteration: 5, Log-Lik: -15598.282, Max-Change: 0.07978
Iteration: 6, Log-Lik: -15597.586, Max-Change: 0.08329
Iteration: 7, Log-Lik: -15596.777, Max-Change: 0.01447
Iteration: 8, Log-Lik: -15596.617, Max-Change: 0.01049
Iteration: 9, Log-Lik: -15596.510, Max-Change: 0.00933
Iteration: 10, Log-Lik: -15596.312, Max-Change: 0.00536
Iteration: 11, Log-Lik: -15596.279, Max-Change: 0.00505
Iteration: 12, Log-Lik: -15596.254, Max-Change: 0.00459
Iteration: 13, Log-Lik: -15596.167, Max-Change: 0.00122
Iteration: 14, Log-Lik: -15596.164, Max-Change: 0.00134
Iteration: 15, Log-Lik: -15596.162, Max-Change: 0.00130
Iteration: 16, Log-Lik: -15596.154, Max-Change: 0.00035
Iteration: 17, Log-Lik: -15596.154, Max-Change: 0.00035
Iteration: 18, Log-Lik: -15596.154, Max-Change: 0.00034
Iteration: 19, Log-Lik: -15596.153, Max-Change: 0.00028
Iteration: 20, Log-Lik: -15596.153, Max-Change: 0.00025
Iteration: 21, Log-Lik: -15596.153, Max-Change: 0.00024
Iteration: 22, Log-Lik: -15596.153, Max-Change: 0.00028
Iteration: 23, Log-Lik: -15596.153, Max-Change: 0.00018
Iteration: 24, Log-Lik: -15596.153, Max-Change: 0.00017
Iteration: 25, Log-Lik: -15596.153, Max-Change: 0.00018
Iteration: 26, Log-Lik: -15596.153, Max-Change: 0.00014
Iteration: 27, Log-Lik: -15596.153, Max-Change: 0.00014
Iteration: 28, Log-Lik: -15596.153, Max-Change: 0.00016
Iteration: 29, Log-Lik: -15596.153, Max-Change: 0.00013
Iteration: 30, Log-Lik: -15596.153, Max-Change: 0.00013
Iteration: 31, Log-Lik: -15596.153, Max-Change: 0.00012
Iteration: 32, Log-Lik: -15596.153, Max-Change: 0.00012
Iteration: 33, Log-Lik: -15596.153, Max-Change: 0.00012
Iteration: 34, Log-Lik: -15596.153, Max-Change: 0.00011
Iteration: 35, Log-Lik: -15596.153, Max-Change: 0.00011
Iteration: 36, Log-Lik: -15596.153, Max-Change: 0.00011
Iteration: 37, Log-Lik: -15596.153, Max-Change: 0.00011
Iteration: 38, Log-Lik: -15596.153, Max-Change: 0.00011
Iteration: 39, Log-Lik: -15596.153, Max-Change: 0.00053
Iteration: 40, Log-Lik: -15596.153, Max-Change: 0.00048
Iteration: 41, Log-Lik: -15596.153, Max-Change: 0.00035
Iteration: 42, Log-Lik: -15596.153, Max-Change: 0.00025
Iteration: 43, Log-Lik: -15596.153, Max-Change: 0.00048
Iteration: 44, Log-Lik: -15596.153, Max-Change: 0.00031
Iteration: 45, Log-Lik: -15596.153, Max-Change: 0.00022
Iteration: 46, Log-Lik: -15596.153, Max-Change: 0.00045
Iteration: 47, Log-Lik: -15596.153, Max-Change: 0.00030
Iteration: 48, Log-Lik: -15596.153, Max-Change: 0.00022
Iteration: 49, Log-Lik: -15596.153, Max-Change: 0.00042
Iteration: 50, Log-Lik: -15596.153, Max-Change: 0.00031
Iteration: 51, Log-Lik: -15596.153, Max-Change: 0.00022
Iteration: 52, Log-Lik: -15596.153, Max-Change: 0.00040
Iteration: 53, Log-Lik: -15596.153, Max-Change: 0.00034
Iteration: 54, Log-Lik: -15596.153, Max-Change: 0.00024
Iteration: 55, Log-Lik: -15596.153, Max-Change: 0.00008
# extract the item parameters
cacParams <- coef(cacIRTModel,
                  IRTpars = TRUE,
                  as.data.frame = TRUE)
cacTheta <- fscores(cacIRTModel, method = "EAP")
cacTheta <- as.data.frame(cacTheta)

# packages seems to be picky about which data type it wants (data.frame vs matrix)
cacParams <- as.data.frame(cacParams)
# had to do some data wrangling to get the item parameters in the right format, outside of R
cacParams_BTF1 <- read_excel("BoomTruck/BT_IRTParams_Form1.xlsx", 
    col_types = c("text", "numeric"))

# some additional unnecesary data wrangling for the Lee and Rudner methods
cacParams_BTF1 <- cacParams_BTF1 %>%
  separate(col = ItemID, into = c("key", "suffix"), sep = "\\.") %>%
  pivot_wider(names_from = suffix, values_from = Param) %>%
  select(-key,-u)

# the pnr method prefers a matrix, not a data frame
cacData <- as.matrix(cacData)
# simple code to run the pnr method
pnr.out <- pnr(cacData)

# pnr results are in a list of 3, so we must extract the results
resultsNP <- Lee.pnr(48, pnr.out)

resultsNP[["Marginal"]]
##            Accuracy Consistency
## cut at 48 0.9340462   0.9067493
resultsNP[["Conditional"]][["Accuracy"]]
##     cut at 48
## 0  1.00000000
## 1  1.00000000
## 2  1.00000000
## 3  1.00000000
## 4  1.00000000
## 5  1.00000000
## 6  0.12026583
## 7  0.02220855
## 8  0.02130056
## 9  0.02128862
## 10 0.02128854
## 11 0.02128853
## 12 0.02128854
## 13 0.02128860
## 14 0.02129832
## 15 0.02198138
## 16 0.06599138
## 17 1.00000000
## 18 1.00000000
## 19 1.00000000
## 20 1.00000000
## 21 1.00000000
## 22 1.00000000
## 23 1.00000000
## 24 1.00000000
## 25 1.00000000
## 26 1.00000000
## 27 1.00000000
## 28 1.00000000
## 29 1.00000000
## 30 1.00000000
## 31 1.00000000
## 32 1.00000000
## 33 0.99999999
## 34 0.99999937
## 35 1.00000000
## 36 0.99999574
## 37 0.99981530
## 38 0.99999447
## 39 0.99847151
## 40 0.99379276
## 41 0.98422621
## 42 0.96257073
## 43 0.93459520
## 44 0.87187568
## 45 0.79306083
## 46 0.68594009
## 47 0.55866496
## 48 0.57938981
## 49 0.71149609
## 50 0.83030626
## 51 0.91048011
## 52 0.96118174
## 53 0.98715432
## 54 0.99679430
## 55 0.99955814
## 56 0.99997045
## 57 0.99999944
## 58 1.00000000
## 59 1.00000000
## 60 1.00000000
resultsNP[["Consistency"]]
##    cut at 48
## 0  1.0000000
## 1  1.0000000
## 2  1.0000000
## 3  1.0000000
## 4  1.0000000
## 5  1.0000000
## 6  0.7883961
## 7  0.9565693
## 8  0.9583063
## 9  0.9583292
## 10 0.9583293
## 11 0.9583293
## 12 0.9583293
## 13 0.9583292
## 14 0.9583106
## 15 0.9570036
## 16 0.8767270
## 17 1.0000000
## 18 1.0000000
## 19 1.0000000
## 20 1.0000000
## 21 1.0000000
## 22 1.0000000
## 23 1.0000000
## 24 1.0000000
## 25 1.0000000
## 26 1.0000000
## 27 1.0000000
## 28 1.0000000
## 29 1.0000000
## 30 1.0000000
## 31 1.0000000
## 32 1.0000000
## 33 1.0000000
## 34 0.9999987
## 35 1.0000000
## 36 0.9999915
## 37 0.9996307
## 38 0.9999889
## 39 0.9969477
## 40 0.9876626
## 41 0.9689500
## 42 0.9279434
## 43 0.8777460
## 44 0.7765830
## 45 0.6717693
## 46 0.5691474
## 47 0.5068832
## 48 0.5126055
## 49 0.5894612
## 50 0.7182045
## 51 0.8369878
## 52 0.9253772
## 53 0.9746387
## 54 0.9936091
## 55 0.9991167
## 56 0.9999409
## 57 0.9999989
## 58 1.0000000
## 59 1.0000000
## 60 1.0000000