diff --git a/DESCRIPTION b/DESCRIPTION index 50448ae..fb6031a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -23,9 +23,12 @@ Imports: vetiver (>= 0.2.1) Suggests: jsonlite, + knitr, plotly, + rmarkdown, spelling, testthat (>= 3.0.0) +VignetteBuilder: knitr RoxygenNote: 7.3.3 Language: en-US Config/testthat/edition: 3 diff --git a/vigenettes/accept3_cprd_vignette.Rmd b/vigenettes/accept3_cprd_vignette.Rmd new file mode 100644 index 0000000..3df4373 --- /dev/null +++ b/vigenettes/accept3_cprd_vignette.Rmd @@ -0,0 +1,243 @@ +--- +title: "ACCEPT 3.0-CPRD: Predicting COPD Exacerbation Risk in UK Primary Care" +output: rmarkdown::html_vignette +vignette: > + %\VignetteEncoding{UTF-8} + %\VignetteIndexEntry{ACCEPT 3.0-CPRD: Predicting COPD Exacerbation Risk in UK Primary Care} + %\VignetteEngine{knitr::rmarkdown} +editor_options: + markdown: + wrap: 72 +--- + +```{r setup, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +library(accept) +``` + +## Overview + +`accept3_cprd()` implements ACCEPT 3.0-CPRD, a recalibration of the +ACCEPT 2.0 model specifically for UK primary-care patients. It was +derived from the **Clinical Practice Research Datalink (CPRD)**, a large +UK primary-care database, and is designed to produce well-calibrated +1-year exacerbation risk predictions in this setting. + +The function predicts two outcomes: + +- **Moderate-to-severe exacerbation** probability and rate +- **Severe exacerbation** probability and rate + +It can also be called via the unified `accept()` interface using +`country = "GBR-primary"`. + +------------------------------------------------------------------------ + +## When to Use ACCEPT 3.0-CPRD + +| Model | Population | Setting | +|-------------------|-----------------------------|------------------------| +| `accept2()` | Canadian/international | Hospital or specialist | +| `accept3()` / `accept3_gbr()` | UK | Secondary care | +| **`accept3_cprd()`** | **UK** | **Primary care (GP)** | + +Use `accept3_cprd()` when your patients are from a **UK general +practice** setting, where disease severity tends to be milder and fewer +specialist measurements are routinely available. + +------------------------------------------------------------------------ + +## Required Identifier + +The following column is required but is **not** a predictor — it is used +solely to label rows in the output so predictions can be matched back to +patients: + +| Column | Type | Description | +|--------|-------------------|---------------------------| +| `ID` | character/numeric | Unique patient identifier | + +------------------------------------------------------------------------ + +## Required Predictors + +The following columns are the actual **model inputs** and must be +present in your data: + +| Column | Type | Description | +|---------------------|------------------|----------------------------------| +| `age` | numeric | Age in years | +| `male` | integer (0/1) | Sex (1 = male) | +| `FEV1` | numeric | FEV1 % predicted | +| `LastYrExacCount` | integer | Total exacerbations in the past year (moderate + severe) | +| `LastYrSevExacCount` | integer | Severe (hospitalised) exacerbations in the past year | +| `mMRC` **or** `SGRQ` | numeric | Dyspnoea score (mMRC 0–4) or SGRQ total score | + +> **Note:** `LastYrSevExacCount` must not exceed `LastYrExacCount`. At +> least one of `mMRC` or `SGRQ` must be provided; if only `SGRQ` is +> available it is converted to `mMRC` internally. + +------------------------------------------------------------------------ + +## Optional Predictors + +These columns are used if available; if missing they are **automatically +imputed** using a CPRD-specific sequential triangular regression model: + +| Column | Type | Description | +|----------|---------------|---------------------------------------| +| `LABA` | integer (0/1) | Long-acting beta-agonist use | +| `oxygen` | integer (0/1) | Long-term oxygen therapy | +| `ICS` | integer (0/1) | Inhaled corticosteroid use | +| `LAMA` | integer (0/1) | Long-acting muscarinic antagonist use | +| `statin` | integer (0/1) | Statin or CVD medication use | +| `BMI` | numeric | Body mass index (clamped to 10–60) | +| `smoker` | integer (0/1) | Current smoker | + +Imputation proceeds in the order above. Each variable is predicted from +the mandatory predictors plus any previously imputed optional +predictors. + +------------------------------------------------------------------------ + +## Basic Usage + +```{r basic, eval = FALSE} +library(accept) + +# Using the sample patients bundled with the package +results <- accept3_cprd(samplePatients) +head(results) +``` + +```{r basic_show, echo = FALSE} +# Example output structure (not run) +cat( +"# A tibble: 6 x 4 + predicted_exac_probability predicted_exac_rate predicted_severe_exac_probability predicted_severe_exac_rate + +1 0.699 1.20 0.356 0.439 +2 0.324 0.392 0.0415 0.0424 +...") +``` + +------------------------------------------------------------------------ + +## Accessing Results via `accept()` + +You can also call `accept3_cprd` through the unified interface: + +```{r unified, eval = FALSE} +results <- accept( + newdata = samplePatients, + version = "accept3", + country = "GBR-primary" +) +``` + +------------------------------------------------------------------------ + +## Including Predictors in the Output + +Set `return_predictors = TRUE` to include the input columns alongside +predictions. This is useful for checking which values were imputed: + +```{r return_preds, eval = FALSE} +results_full <- accept3_cprd(samplePatients, return_predictors = TRUE) +names(results_full) +``` + +------------------------------------------------------------------------ + +## Imputation Messages + +By default, imputation is silent. Set `quiet = FALSE` to see which +predictors were imputed for each patient: + +```{r quiet, eval = FALSE} +results <- accept3_cprd(samplePatients, quiet = FALSE) +# Example message: +# Patient 3: imputed LABA, BMI, smoker +``` + +------------------------------------------------------------------------ + +## Handling Missing mMRC / SGRQ + +The function requires either `mMRC` (0–4) or `SGRQ` (0–100). If only +`SGRQ` is provided, it is converted to `mMRC` using the published +conversion formula before prediction. If neither is available, an error +is raised. + +```{r sgrq, eval = FALSE} +# Data with SGRQ instead of mMRC +patients_sgrq <- samplePatients +patients_sgrq$mMRC <- NULL # remove mMRC +patients_sgrq$SGRQ <- c(45, 30, 60, 20, 55, 10) # add SGRQ + +results <- accept3_cprd(patients_sgrq) +``` + +------------------------------------------------------------------------ + +## Recalibration Method + +ACCEPT 3.0-CPRD applies a Cox-model recalibration to ACCEPT 2.0 +predictions: + +$$\hat{p}_{UK} = 1 - \exp\!\left(-H_0 \cdot \exp\!\left(\beta \cdot \log(-\log(1-\hat{p}_{2}))\right)\right)$$ + +where $\hat{p}_{2}$ is the ACCEPT 2.0 predicted probability, and $H_0$ +and $\beta$ are optimism-corrected parameters estimated via 200-resample +bootstrap from the CPRD dataset: + +| Outcome | $H_0$ | $\beta$ | +|--------------------|-------|---------| +| Moderate-to-severe | 0.676 | 0.986 | +| Severe | 0.482 | 1.124 | + +------------------------------------------------------------------------ + +## Comparing Models + +```{r compare, eval = FALSE} +library(accept) +library(dplyr) + +patients <- samplePatients + +a2 <- accept2(patients) +a3 <- accept3_cprd(patients) + +comparison <- bind_cols( + ID = patients$ID, + accept2 = a2$predicted_exac_probability, + accept3uk = a3$predicted_exac_probability +) + +print(comparison) +``` + +Predictions from ACCEPT 3.0-CPRD are generally **lower** than ACCEPT 2.0 +for moderate-to-severe exacerbations, reflecting the milder disease +burden typically seen in UK primary care compared with specialist +settings. + +------------------------------------------------------------------------ + +## See Also + +- `accept()` — unified interface for all ACCEPT model versions +- `accept3()` / `accept3_gbr()` — ACCEPT 3.0 UK secondary-care version +- `samplePatients` — example dataset + +------------------------------------------------------------------------ + +## Session Info + +```{r session, eval = FALSE} +sessionInfo() +```