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.
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.
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.
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"))
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.