---
title: "Continuous drift monitoring for an item bank"
output: markdown::html_format
vignette: >
  %\VignetteIndexEntry{Continuous drift monitoring for an item bank}
  %\VignetteEngine{knitr::knitr}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```

Most drift checks compare two calibrations at equating time. driftwatch
monitors every calibration window and asks *when* an item started drifting,
*how* (gradual trend or abrupt jump), and *what to do about it*.

## Data

A bank of 120 items is administered over 30 windows. In the simulation, some
items drift gradually and some jump abruptly.

```{r}
library(driftwatch)
sim <- dw_simulate(n_items = 120, n_windows = 30, mean_n = 70,
                   onset_range = c(5, 18), seed = 7)
table(sim$truth$type)
```

## Window estimates

```{r}
est <- dw_estimate(sim$responses, sim$bank)
round(est$z[1:4, 1:8], 2)
```

## Set the alarm threshold for your bank

`dw_tune()` regenerates your own design under no drift and picks the CUSUM
threshold that gives the target false-alarm probability per item over the
horizon.

```{r}
tu <- dw_tune(est, target = 0.02, n_rep = 4, seed = 1)
tu$h
```

## Monitor

```{r}
mon <- dw_monitor(est, h = tu$h)
mon
table(alarm = mon$items$alarm, truth = sim$truth$type)
```

Soon after an alarm, a short ramp can look like a step; such items are marked
`undetermined` until more windows arrive.

## Act, and record why

```{r}
log <- dw_actions(mon, anchors = sim$bank$item[1:20], analyst = "psychometrics")
head(log[c("item", "alarm_window", "type", "magnitude", "action")])
```

## What does drift do to scores?

```{r}
flagged <- mon$items$item[mon$items$alarm]
drifted <- sim$truth$item[sim$truth$type != "stable"]
form <- c(head(drifted, 8), head(setdiff(sim$bank$item, drifted), 32))
last <- est$b_hat[, ncol(est$b_hat)]
dw_impact(form, sim$bank, sim$b_path[, ncol(sim$b_path)], flagged,
          recalibrated = last[flagged], cut = 0.5)
```
