---
title: "Getting started with iPEB"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting started with iPEB}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
set.seed(1)   # ipeb() draws an internal validation split; fix it for a reproducible vignette
```

## Overview

`iPEB` (improved Parametric Empirical Bayes) analyses longitudinal biomarker
data for early-detection screening. It combines a *time-gap-aware*
standardization layer with *objective-driven* multi-marker weighting: each
subject's history is modelled so that prediction uncertainty grows with the gap
between visits, and marker weights are learned to optimize a clinical objective
you choose rather than opaque tuning parameters.

```{r}
library(iPEB)
data(ipeb_example)
str(ipeb_example)
```

The data are in long format: one row per subject-visit, with a subject `id`, a
`case` indicator (1 = case, 0 = control), a visit `time` (years since the first
visit), `time_to_dx` (days from the visit to diagnosis), and biomarkers
`m1`--`m3`.

```{r}
train <- subset(ipeb_example, split == "train")
test  <- subset(ipeb_example, split == "test")
```

## Fitting a model

`ipeb()` fits on the training data. Here we optimize sensitivity at 95%
specificity. (We use i.i.d. innovations and no random slope purely to keep this
vignette fast; the defaults `innovation = "auto"` and `slope = "auto"` choose
gap-aware AR(1)/OU innovations and a slope when the data support them.)

```{r}
fit <- ipeb(train, markers = c("m1", "m2", "m3"),
            objective = "sensitivity", alpha = 0.95,
            innovation = "iid", slope = "off")
fit
```

The printed summary shows the chosen combiner variant (scalar or multivariate),
the operating specificity, the layer configuration, and the learned weights.

## Scoring and evaluating new subjects

`predict()` returns a per-visit iPEB score for new data, and `evaluate()`
reports per-patient sensitivity and median lead time with per-visit specificity
at the operating points you request. Thresholds are calibrated on the training
controls and applied unchanged to the test subjects.

```{r}
head(predict(fit, test))

evaluate(fit, test, specificities = c(0.90, 0.95, 0.99))
```

## Changing the objective

The same markers can be optimized for a different clinical goal. The lead-time
objective rewards earlier detection while retaining sensitivity:

```{r}
fit_lt <- ipeb(train, markers = c("m1", "m2", "m3"),
               objective = "leadtime", innovation = "iid", slope = "off")
evaluate(fit_lt, test, specificities = 0.95)
```

## Feature selection

When a smaller panel is preferred, iPEB can select markers by objective-driven
backward elimination to a target size:

```{r}
fit_sel <- ipeb(train, markers = c("m1", "m2", "m3"),
                objective = "sensitivity", select = "backward", n_markers = 2,
                innovation = "iid", slope = "off")
fit_sel$markers
```

## One-call workflow

`ipeb_run()` fits and evaluates in a single call:

```{r}
res <- ipeb_run(train, test, markers = c("m1", "m2", "m3"),
                objective = "sensitivity", innovation = "iid", slope = "off",
                specificities = c(0.90, 0.95, 0.99))
res$evaluation
```

## Notes

* Sensitivity and lead time are per patient over the whole pre-diagnostic
  trajectory; a subject is detected if *any* pre-diagnostic visit crosses the
  threshold. A `window` (in months) may be supplied to restrict the objective to
  a fixed horizon, but the default uses the whole trajectory.
* Specificity is per visit and is calibrated on the training controls, so the
  threshold set at fitting is applied unchanged to new data.
