#################################################################################### # L10 - Computerized adaptive testing # # NMST570 # # Last update: 06/01/2020 # #################################################################################### # Slides available at http://www.cs.cas.cz/martinkova/NMST570.html # HW assignment available at http://www.cs.cas.cz/hladka/documents/NMST570_HW10.pdf #################################################################################### # Loading packages ################################################################# #################################################################################### library(mirtCAT) options(stringsAsFactors = FALSE) #################################################################################### # Create simple non-adaptive interface ############################################# #################################################################################### # Questions questions <- c("Building CATs with mirtCAT is difficult.", "Building tests with mirtCAT requires a lot of coding.", "I would use mirtCAT in my research.") # Potential options for each item options <- matrix(c("Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"), nrow = 3, ncol = 5, byrow = TRUE) df <- data.frame(Question = questions, Option = options, Type = "radio") df # Run the mirtCAT web interface and store results ?mirtCAT result1 <- mirtCAT(df = df) print(result1) summary(result1) #--------------------------------------------- # Ex. 1.1 #--------------------------------------------- # Create your own non-adaptive interface with at least 3 questions # You can use different types of responses # (see argument df and Type in help of mirtCAT) #################################################################################### # Adding the demographics page ##################################################### #################################################################################### # Include a demographics page to collect occupation and gender variables demographics <- list(textInput(inputId = 'occupation', label = 'What is your occupation?', value = ''), selectInput(inputId = 'gender', label = 'Please select your gender.', choices = c('', 'Male', 'Female', 'Other'), selected = '')) # Run the mirtCAT web interface and store results result2 <- mirtCAT(df, shinyGUI = list(demographics = demographics, demographics_inputIDs = c('occupation', 'gender'))) summary(result2) #--------------------------------------------- # Ex. 1.2 #--------------------------------------------- # Add some demographics into your own interface from Ex. 1 # Change title and authors via argument shinyGUI argument: # e.g. shinyGUI(title = "My title", # authors = "Me") ?mirtCAT #################################################################################### # Unidimensional CAT ############################################################### #################################################################################### # Define IRT item parameters (not IRT parameterization!) set.seed(1234) ### Number of items nitems <- 100 ### Item names itemnames <- paste0('Item.', 1:nitems) ### Discrimination a <- matrix(round(rlnorm(nitems, .2, .3), 2)) ### Location parameter ("difficulty") d <- matrix(round(rnorm(nitems), 2)) ### Parameters, pseudo-guessing 0.2 for all items (pars <- data.frame(a1 = a, d = d, g = 0.2)) ### Create 3PL model - mirt object mod <- generate.mirt_object(pars, '3PL') # Define questions and possible answers # Math questions for addition questions <- answers <- character(nitems) choices <- matrix('a', nitems, 5) spacing <- floor(d - min(d)) + 1 # easier items have more variation for(i in 1:nitems){ # generate number from 1 to 100 n1 <- sample(1:100, 1) # generate number from 101 to 200 n2 <- sample(101:200, 1) # sum generated numbers ans <- n1 + n2 # create question questions[i] <- paste0(n1, ' + ', n2, ' = ?') answers[i] <- as.character(ans) # create distractors ch <- ans + sample(c(-5:-1, 1:5) * spacing[i, ], 5) ch[sample(1:5, 1)] <- ans choices[i, ] <- as.character(ch) } df <- data.frame(Questions = questions, Answer = answers, Option = choices, Type = 'radio') head(df) # Run the mirtCAT web interface and store results my_result <- mirtCAT(df, mod, method = 'EAP', criteria = 'MI', start_item = 1, design = list(min_SEM = 0.6, min_items = 10)) print(my_result) plot(my_result) summary(my_result) #--------------------------------------------- # Ex. 1.3 #--------------------------------------------- # Run the previous CAT and answer following questions: # 1. How many items did you answer until the stopping criteria were met? # 2. Which stopping criterion was met? # 3. What is your estimated ability theta? What is its standard error? #################################################################################### # Offline example ################################################################## #################################################################################### # Using previous assingment and framework, generate random response pattern set.seed(123) pattern <- generate_pattern(mod, Theta = 1) print(pattern) result4 <- mirtCAT(mo = mod, local_pattern = pattern, start_item = 1, criteria = "MEPV", design = list(min_SEM = 0.6, min_items = 10)) print(result4) summary(result4) plot(result4) #--------------------------------------------- # Ex. 1.4 #--------------------------------------------- # Run the previous CAT and answer following questions: # 1. How many items were assigned? Which items were assigned? # 2. Provide estimate of ability theta and its standard error. #################################################################################### # Multidimensional example ######################################################### #################################################################################### # This example demonstrates how a multidimensional IRT test can be scored and # modified for offline and on-line use. As well, it compares the effect of scoring # the entire test given all possible responses to the use of a CAT scheme. The final # section demonstrates how various elements in the GUI can be modified for more # customized presentations. # The following code-block defines 100 items for a two factor math test measuring # addition and multiplication. # define population IRT parameters set.seed(1234) nitems <- 120 itemnames <- paste0("Item.", 1:nitems) a <- matrix(c(rlnorm(nitems/2, 0.2, 0.3), rnorm(nitems/4, 0, 0.3), numeric(nitems/2), rnorm(nitems/4, 0, 0.3), rlnorm(nitems/2, 0.2, 0.3)), nitems) d <- matrix(rnorm(nitems)) pars <- data.frame(a, d) colnames(pars) <- c("a1", "a2", "d") # addition and multiplication are positively correlated trait_cov <- matrix(c(1, 0.5, 0.5, 1), 2, 2) # create mirt_object mod <- generate.mirt_object(pars, itemtype = "2PL", latent_covariance = trait_cov) # math items definitions addition for one factor and multiplication for the other questions <- answers <- character(nitems) options <- matrix("", nitems, 5) spacing <- floor(d - min(d)) + 1 # easier items have more variation for (i in 1:nitems) { if (i < 31) { # addition n1 <- sample(1:100, 1) n2 <- sample(101:200, 1) ans <- n1 + n2 questions[i] <- paste0(n1, " + ", n2, " = ?") } else if (i < 61) { # addition and multiplication n1 <- sample(1:50, 1) n2 <- sample(51:100, 1) m1 <- sample(1:10, 1) m2 <- sample(1:10, 1) ans <- n1 + n2 + m1 * m2 questions[i] <- paste0(n1, " + ", n2, " + ", m1, " * ", m2, " = ?") } else if (i < 91) { # multiplication and addition n1 <- sample(1:10, 1) n2 <- sample(1:10, 1) m1 <- sample(1:25, 1) m2 <- sample(1:25, 1) ans <- n1 + n2 + m1 * m2 questions[i] <- paste0(m1, " * ", m2, " + ", n1, " + ", n2, " = ?") } else { # multiplication m1 <- sample(1:50, 1) m2 <- sample(1:50, 1) ans <- n1 + n2 + m1 * m2 questions[i] <- paste0(m1, " * ", m2, " = ?") } answers[i] <- as.character(ans) ch <- ans + sample(c(-5:-1, 1:5) * spacing[i, ], 5) ch[sample(1:5, 1)] <- ans options[i, ] <- as.character(ch) } # load list of items and their answers df <- data.frame(Question = questions, Option = options, Answer = answers, Type = "radio") head(df) tail(df) set.seed(1234) # theta is now two-dimensional (addition and multiplication) pat <- generate_pattern(mo = mod, Theta = c(1, 0.5), df = df) head(pat) #--------------------------------------------- # Set min_items to number of items in bank - fixed linear testing result5a <- mirtCAT(df = df, mo = mod, local_pattern = pat, design = list(min_items = 120)) print(result5a) summary(result5a) plot(result5a, scales = list(x = list(at = NULL))) #--------------------------------------------- # MCAT using D-rule result5b <- mirtCAT(df = df, mo = mod, criteria = "Drule", local_pattern = pat, start_item = "Drule", design = list(min_SEM = 0.3)) print(result5b) summary(result5b) plot(result5b, scales = list(x = list(at = NULL))) #--------------------------------------------- # Ex. 1.5 #--------------------------------------------- # Run the previous MCAT and answer following questions: # 1. How many items were assigned using fixed linear testing and MCAT? # 2. Provide estimates of ability theta and their standard error using fixed linear testing and MCAT.