Getting Started with readmit

knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(readmit)

Readmission Risk Pool (RRP) estimates the probability of a first readmission strictly after an assessment time through 30 elapsed days after discharge. The endpoint stays anchored to the original discharge. readmit supplies the project, eligibility, history, and product operations; the project owner supplies the source mapping and risk provider.

This small example uses one fixed analytical time and an illustrative formula. It does not provide a clinically validated model. For source mapping, a trained assessment-time model, repeated assessments, and application customization, see Implementing RRP: A Simulated Hospital Walkthrough.

Create a project and supply canonical facts

Initialization creates an ordinary project directory. Its R/produce-canonical.R and R/calculate-risk.R scripts are the owner's two analytical implementation points. We replace their initial stubs below.

project <- rrp_project_init(tempfile("rrp-getting-started-"), "example-rrp")
as_of_time <- as.POSIXct("2026-01-10 12:00:00", tz = "UTC")
discharge_time <- as.POSIXct(c(
  "2026-01-08 12:00:00", "2026-01-01 12:00:00",
  "2025-12-01 12:00:00", "2026-01-04 12:00:00"
), tz = "UTC")
episodes <- data.frame(
  episode_id = paste0("episode-", 1:4),
  patient_id = paste0("patient-", 1:4),
  index_encounter_id = paste0("encounter-", 1:4),
  admission_time = discharge_time - 2 * 86400,
  discharge_time = discharge_time
)
events <- data.frame(
  terminal_event_id = c("event-2", "event-4"),
  episode_id = c("episode-2", "episode-4"),
  event_type = c("readmission", "death"),
  occurred_at = as.POSIXct(c(
    "2026-01-06 12:00:00", "2026-01-07 12:00:00"
  ), tz = "UTC"),
  available_at = as.POSIXct(c(
    "2026-01-07 12:00:00", "2026-01-08 12:00:00"
  ), tz = "UTC")
)
saveRDS(list(discharge_episode = episodes, terminal_event = events),
        file.path(project, "canonical.rds"))

All four episodes were discharged by this assessment time. Episode 1 is still eligible, episode 2 has a known readmission, episode 3 has passed its original 30-day endpoint, and episode 4 has a known death. The event occurrence and availability times are separate UTC facts. An operational source mapper should select the complete relevant discharge population for each assessment time; this saved list is only a one-snapshot example.

The project-authored mapper reads those typed facts. The provider's illustrative probability is 0.30 scaled by the share of the original 30-day interval still remaining. It uses the package's remaining_seconds request field, so it does not restart the follow-up window. This formula has no clinical meaning.

writeLines(c(
  "rrp_produce_canonical <- function(project_root, as_of_time) {",
  "  readRDS(file.path(project_root, 'canonical.rds'))",
  "}"
), file.path(project, "R", "produce-canonical.R"))
writeLines(c(
  "rrp_calculate_risk <- function(project_root, request) {",
  "  list(probability = 0.30 * request$remaining_seconds / (30 * 86400))",
  "}"
), file.path(project, "R", "calculate-risk.R"))
rrp_project_validate(project)
rrp_state_init(project)

rrp_project_validate() checks that required project resources and functions load. It does not test the supplied data, formula, or clinical suitability.

Run and inspect an assessment

assessment <- rrp_run(project, as_of_time)
assessment[c("episodes_processed", "accepted", "provider_failures", "ineligible")]

status <- rrp_project_status(project)
status[c("state_initialized", "run_count")]
history <- rrp_inspect_history(project)
history[c("episode_id", "disposition", "probability")]
stopifnot(assessment$accepted == 1L, assessment$ineligible == 3L,
          isTRUE(all.equal(history$probability[history$disposition == "accepted"],
                           0.28)))

The package called the provider only for eligible episode 1 and retained its 0.28 illustrative estimate. The other three rows explain why those episodes were ineligible. History remains available for later inspection.

Refresh the three products

Products are derived from retained history; refreshing them does not repeat the assessment or edit the project-owned application.

products <- rrp_refresh_products(project)
current_risk <- read.csv(products$files[["current_risk"]])
trajectory <- read.csv(products$files[["trajectory"]])
scope <- read.csv(products$files[["scope"]])

current_risk[c("episode_id", "disposition", "probability")]
trajectory[c("episode_id", "probability")]
scope[c("episodes_assessed", "eligible_count", "accepted_count",
        "known_readmission_count", "known_death_count", "window_closed_count")]
stopifnot(nrow(current_risk) == 1L, nrow(trajectory) == 1L,
          scope$episodes_assessed == 4L)

The current-risk CSV contains eligible episode 1; the trajectory CSV contains its recorded accepted estimate; and the scope CSV counts all four outcomes. The project-contained Shiny app reads these products. After installing its runtime packages as listed in the project's README.md, launch it manually:

shiny::runApp(file.path(project, "app"))


Try the readmit package in your browser

Any scripts or data that you put into this service are public.

readmit documentation built on Nov. 4, 2026, 1:15 a.m.