--- title: "Model-based flagging of repeat test-takers" output: markdown::html_format vignette: > %\VignetteIndexEntry{Model-based flagging of repeat test-takers} %\VignetteEngine{knitr::knitr} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` Flagging repeaters on raw score gain punishes candidates who studied or remediated. retestR asks a different question: is this gain larger than *this* candidate's circumstances predict, and is it concentrated where preknowledge would put it? ## Data Each repeater took two disjoint forms drawn from a calibrated bank in which every item is marked either `exposed` (long-running, possibly compromised) or new. The simulation plants preknowledge in 5% of repeaters. ```{r} library(retestR) sim <- rt_simulate(n_persons = 800, form_exposed = 30, form_new = 15, seed = 1) head(sim$data$persons) table(sim$truth$preknowledge) ``` With real data, assemble the same structure with `rt_data(responses, persons, bank)`. ## Expected gain The growth model uses attempt 1 and only the *new* items of attempt 2, so preknowledge cannot inflate the expected gain. ```{r} fit <- rt_fit(sim, growth = ~ log(days_between) + remediation) fit ``` ## Evidence and risk ```{r} risk <- rt_risk(fit, n_null = 4, alpha = 0.01, seed = 1) risk ``` `p_value` is calibrated by simulating complete honest administrations through the same pipeline, so it is the false-positive rate for an honest repeater. ```{r} table(flagged = risk$flag, preknowledge = sim$truth$preknowledge) ``` ## Compared with raw-gain flagging Flag the same number of candidates by raw gain and look at who gets caught: ```{r} raw <- rt_raw_gain(sim) k <- sum(risk$flag) raw_flag <- raw$gain >= sort(raw$gain, decreasing = TRUE)[k] honest_remediated <- !sim$truth$preknowledge & sim$truth$remediation == 1 c(model_caught = sum(risk$flag & sim$truth$preknowledge), raw_caught = sum(raw_flag & sim$truth$preknowledge), model_flags_remediated = sum(risk$flag & honest_remediated), raw_flags_remediated = sum(raw_flag & honest_remediated)) ```