---
title: Person assessment with PPass, also for eRm models
author: Manuel Reif
output: rmarkdown::html_vignette
vignette: >
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteIndexEntry{Person assessment with PPass, also for eRm models}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
has_erm <- requireNamespace("eRm", quietly = TRUE)
```

`PPass()` (**P**erson **P**arameter **ass**essment) estimates the abilities, computes the person fit and returns both in one table, together with the other person variables. It accepts

- a data.frame (or matrix) with item responses, together with known item parameters, or
- a model fitted with the eRm package: the Rasch model, the linear logistic test model, the rating scale model, the partial credit model and their linear versions, also with several time points and groups.

## Data with item parameters

`fourpl_df` contains an id, the sex and the responses of 60 persons to 12 items of a 3PL test. `items` names the item columns (positions or names); all other columns are kept as person variables. `mod` chooses the model, and the item parameters must match it.

```{r ppass}
library(PP)
data(fourpl_df)
res <- PPass(fourpl_df, items = 3:14,
             thres = attr(fourpl_df, "diffpar"), slopes = attr(fourpl_df, "slopes"),
             lowerA = attr(fourpl_df, "lowerA"))
res
```

By default, `PPass()` computes WLE estimates and all four person fit statistics (lz, lz\*, infit and outfit). Other arguments of `PP_4pl()`, `PP_gpcm()` and `PPall()` can be passed on, e.g. `type = "mle"` or a prior for `type = "map"`. `summary()` shows the distribution of the estimates, the person fit and the persons flagged by lz\* (two-sided, as in the summary of `Pfit()`):

```{r summary}
s <- summary(res)
```

`plot()` shows the person fit map: lz\* against the estimate, with the critical values of `summary()` and the flagged persons labelled, here by their id. `which = "precision"` shows the measurement precision of the test and `which = "profile"` the answers of single persons (see `?"pp-plots"`).

```{r plot, fig.width = 6, fig.height = 4.5, fig.alt = "lz* of every person against the WLE estimate, flagged persons highlighted and labelled with their id"}
plot(res, label = "id")
```

The result is a data.frame. It can be filtered, merged or written to a file like any other data.frame; `as.data.frame()` drops the extra information.

```{r df}
res[res$sex == "w" & res$status == "ok", c("id", "estimate", "SE", "lzstar")][1:5, ]
knitr::kable(head(as.data.frame(res)[, c("id", "sex", "estimate", "SE", "lzstar", "infit")]),
             digits = 3)
```

`JKpp()` and `PV()` work directly on the result, without estimating again:

```{r jk}
head(JKpp(res)$estimates)
```

The model follows from the item parameters: here `slopes` and `lowerA` make it a 3PL model. A threshold matrix with several thresholds per item gives the PCM (all slopes 1) or the GPCM; together with `lowerA` or `upperA` it gives a test with both dichotomous (4PL) and polytomous (GPCM) items, estimated with `PPall()`.

## Models fitted with eRm

```{r erm-note, echo = FALSE, results = "asis", eval = !has_erm}
cat("*The eRm package is not installed, so the code of this section is shown without results.*\n")
```

eRm estimates item parameters by conditional maximum likelihood; `eRm::person.parameter()` then gives maximum likelihood estimates of the abilities. `PPass()` takes the fitted object and adds WLE, MAP, EAP and robust estimates, the person fit, the jackknife and plausible values.

```{r rm, eval = has_erm}
library(eRm)
rm1 <- RM(raschdat1)
res_rm <- PPass(rm1)
res_rm
```

The maximum likelihood estimates are the same as those of eRm:

```{r rm-mle, eval = has_erm}
res_mle <- PPass(rm1, type = "mle", fitindices = "lzstar")
pp <- person.parameter(rm1)
ok <- res_mle$status == "ok"
max(abs(res_mle$estimate[ok] - pp$theta.table[ok, "Person Parameter"]))
```

eRm stores the parameters of the item categories as easiness parameters. `PPass()` converts them into PP thresholds, so the eRm package is not even needed to run `PPass()` on a saved object. Partial credit and rating scale models are estimated with `PP_gpcm()`, with all slopes equal to 1:

```{r pcm, eval = has_erm}
set.seed(2751)
thres <- rbind(c(-2, -1.2, -0.5, 0), c(-1, 0.3, 1, 1.5), c(0.5, NA, NA, 2))
x <- sim_gpcm(thres = thres, alpha = 1, theta = rnorm(300))
res_pcm <- PPass(PCM(x), type = "map")
summary(res_pcm$estimate)
```

With several time points (`mpoints`) and groups (`groupvec`), every combination of item, time point and group is a virtual item with its own parameters. A person answers the virtual items of their group and gets one ability estimate across all time points. eRm gives no person parameters for models with group contrasts; `PPass()` does:

```{r lpcm, eval = has_erm}
x2 <- sim_gpcm(thres = thres, alpha = 1, theta = rnorm(300, 0.5))
lpcm <- LPCM(cbind(x, x2), mpoints = 2, groupvec = rep(1:2, 150))
res_lpcm <- PPass(lpcm)
res_lpcm
```

Plausible values need a prior, so they require an EAP or MAP estimate, such as `res_pcm` above:

```{r pv, eval = has_erm}
set.seed(1)
pv <- PV(res_pcm, npv = 5)
head(pv$pvdraws, 3)
```
