PITS — Power of an Interrupted Time Series

R-CMD-check License: MIT R >= 4.0

An R package for estimating the statistical power of Interrupted Time Series (ITS) studies, with a focus on healthcare applications.

Use PITS to answer: > “How many months of post-intervention follow-up do I need to reliably detect a meaningful effect in my ITS study?”


Installation

# From GitHub (once published):
# install.packages("remotes")
# remotes::install_github("drdaviddelorenzo/PITS")

# From source:
install.packages("path/to/PITS", repos = NULL, type = "source")

Dependency: nlme (ships with base R). No other dependencies required.


Workflow

Pre-intervention data (CSV or data frame)
             ↓
  estimate_its_params()
             ↓
  baseline, sigma, rho
             ↓
  + level_change  ← your clinical hypothesis
             ↓
  calculate_power() / power_sweep()
             ↓
  Choose n_post that achieves ≥ 80% power

Quick start

library(PITS)

# 1. Load your pre-intervention data (or use the built-in example)
data("example_cfr_data")

# 2. Estimate nuisance parameters
params <- estimate_its_params(example_cfr_data)
#   n_pre     = 24
#   baseline  = 15.0   (mean pre-intervention CFR, %)
#   sigma     = 2.15   (residual SD)
#   rho       = 0.22   (AR(1) autocorrelation)

# 3. Calculate power for a candidate design
result <- calculate_power(
  n_pre        = params$n_pre,
  n_post       = 30,             # planned follow-up months
  baseline     = params$baseline,
  level_change = -3,             # minimum clinically meaningful effect
  sigma        = params$sigma,
  rho          = params$rho,
  n_sim        = 1000,
  seed         = 123
)
result$power_pct      # e.g. 78.4%
result$interpretation # "Borderline (60-79%)"

# 4. Optimise with a sweep
sweep <- power_sweep(
  sweep_post   = c(12, 18, 24, 30, 36, 48),
  n_pre        = params$n_pre,
  baseline     = params$baseline,
  level_change = -3,
  sigma        = params$sigma,
  rho          = params$rho,
  n_sim        = 1000
)
plot_power_curve(sweep)

# 5. One-call shortcut
result <- estimate_and_calculate(
  data         = example_cfr_data,
  level_change = -3,
  n_post       = 30
)

Function reference

Parameter estimation

Function Description
estimate_its_params(data) Estimate all nuisance parameters at once
estimate_baseline(outcome) Baseline (intercept at t = 1)
estimate_sigma(outcome) Residual standard deviation
estimate_rho(outcome) AR(1) autocorrelation
estimate_trend(outcome) Pre-intervention trend (slope)

Power simulation

Function Description
calculate_power(...) Monte Carlo power — single site
calculate_power_multi(sites, ...) Monte Carlo power — multiple sites
power_sweep(sweep_post, ...) Power across a range of n_post values
build_param_grid(...) Factorial parameter grid
run_power_grid(grid, ...) Power across a full parameter grid

Plots and diagnostics

Function Description
plot_power_curve(sweep) Line plot of power vs n_post
plot_power_heatmap(grid) Colour grid of power over two parameters
plot_its_example(...) Simulated ITS series with fitted model
diagnose_params(data) 2×2 diagnostic panel for pre-intervention data

Utilities and wrappers

Function Description
interpret_power(power) Qualitative label (Adequate / Borderline / Underpowered)
validate_params(...) Check parameters before simulation
simulate_predata(...) Generate synthetic pre-intervention data
export_results(result) Save results to CSV and text file
run_its_power(...) Full single-site workflow with console output
estimate_and_calculate(data, ...) Parameter estimation + power in one call

Key parameters

Parameter What it is How to set it
n_pre Pre-intervention time points Fixed — use your historical data
n_post Post-intervention time points Design lever — use power_sweep() to optimise
baseline Mean pre-intervention outcome From estimate_its_params()
sigma Residual SD (noise) From estimate_its_params()
rho AR(1) autocorrelation From estimate_its_params(); use 0.4 if unknown
level_change Minimum meaningful step change Clinical hypothesis — set based on expert judgement
slope_change Minimum meaningful trend change Clinical hypothesis — set to 0 if testing level only
test Effect to test: "level", "slope", or "both" Depends on intervention type

Multi-site designs

sites <- list(
  list(name = "Hospital A", n_pre = 24, n_post = 30,
       baseline = 15, level_change = -3, slope_change = 0,
       sigma = 2.5, rho = 0.4),
  list(name = "Hospital B", n_pre = 24, n_post = 30,
       baseline = 18, level_change = -3, slope_change = 0,
       sigma = 3.0, rho = 0.4)
)
result <- calculate_power_multi(sites, n_sim = 1000, seed = 123)
result$power_pct

References


Citing PITS

@software{PITS_2026,
  title  = {PITS: Power of Interrupted Time Series Studies},
  author = {de Lorenzo, David},
  year   = {2026},
  url    = {https://github.com/drdaviddelorenzo/PITS}
}

Author

David de Lorenzo (ORCID 0000-0003-2042-0961) — UCL Great Ormond Street Institute of Child Health, London, UK; Neotree, London, UK.


Licence

MIT — see LICENSE.