ccwr is an R package for building reproducible
clone-censor-weight (CCW) workflows for target trial emulation.
This repository is meant to be easy to use from a fresh GitHub clone and easy to maintain as a shared collaboration project. The recommended setup uses:
rig to install and switch to the project R versionrenv to restore the same package environment for every
collaboratorgit clone https://github.com/CausalInferenceLab/ccwr.git
cd ccwrrig to install R
4.4.2This project is pinned to R 4.4.2 for
reproducibility.
rig add 4.4.2
rig default 4.4.2If you already have R 4.4.2, you can skip
rig add 4.4.2.
renvOpen R in the project directory and run:
install.packages("renv")
renv::restore()renv::restore() installs the package versions recorded
in renv.lock, so everyone works with the same dependency
set.
Note: this repository includes a .Rprofile file that
activates renv automatically when you open the project in
R.
From the project root:
R CMD INSTALL .Then in R:
library(ccwr)library(ccwr)
data(lungcancer)
arms <- c("Control", "Surgery")
clones <- clone_arms(lungcancer, arms)
policies <- create_policy_A(
arms,
treatment = "surgery",
time_to_treatment = "timetosurgery",
grace_period = 182.62,
outcome = "death",
followup = "fup_obs",
clone_outcome = "outcome",
clone_followup = "fup"
)
clones_policy <- apply_logics(clones, policies)
censoring_logics <- create_censoring_logics_A(
arms,
treatment = "surgery",
time_to_treatment = "timetosurgery",
grace_period = 182.62,
followup = "fup_obs",
clone_censoring = "censoring",
clone_uncensored_followup = "fup_uncensored"
)
clones_censored <- apply_logics(clones_policy, censoring_logics)fup_uncensored is the strategy-specific follow-up time
for the censoring rules. It remains the observed follow-up time when a
clone adheres to its assigned strategy and is set to the
artificial-censoring time only when that clone deviates from the
strategy.
clones_final <- create_final_data(
clones_censored,
clone_followup = "fup",
clone_outcome = "outcome",
clone_censoring = "censoring",
col_ids = "id"
)
clones_estimated <- estimate_censoring(
clones_final,
predictors = c("age", "sex"),
method = "pooled_logit"
)
clones_weighted <- weight_cases(clones_estimated)
fit <- emul_estimate(
clones_weighted,
method = "Cox",
weights = "weight_Cox",
predictors = c("age", "sex")
)
exp(stats::coef(fit))
boot <- emul_estimate_bootstrap(
lungcancer,
arms = arms,
id = "id",
treatment = "surgery",
time_to_treatment = "timetosurgery",
grace_period = 182.62,
outcome = "death",
followup = "fup_obs",
censoring_predictors = c("age", "sex"),
predictors = c("age", "sex"),
n_bootstrap = 200,
seed = 1
)The full process is:
clone_arms().create_policy_A() and apply_logics().create_censoring_logics_A() and
apply_logics().create_final_data().estimate_censoring().weight_cases().emul_estimate().emul_estimate_bootstrap() to resample the original
subjects and repeat the complete workflow when bootstrap confidence
intervals are needed.Pooled-logistic censoring models use a linear interval-start-time
term by default. Set time_spline_df = 3 in
estimate_censoring(), or
censoring_time_spline_df = 3 in
emul_estimate_bootstrap(), to use a natural cubic spline
when the censoring data contain enough events to support the additional
flexibility.
The package currently supports two-arm grace-period strategies for subject-level observational time-to-event data. It includes:
read_trial_data() to read trial-style CSV data into a
tibblemake_surv_response() to build a
survival::Surv() response objectclone_arms() to duplicate observations across treatment
strategiescreate_policy_A() and
create_censoring_logics_A() to generate example
treatment-policy and artificial-censoring logic for the lung cancer
scenarioapply_logics() to apply policy or censoring logic to
cloned datacreate_final_data() to create long-form interval data
for censoring modelsestimate_censoring() and weight_cases() to
estimate censoring probabilities and add IPC weightsemul_estimate() to estimate treatment effectsemul_estimate_bootstrap() to obtain subject-level
bootstrap confidence intervals by repeating cloning, censoring,
weighting, and outcome estimationFor collaborative work, the safest pattern is:
4.4.2 with rig.renv::restore().Useful commands:
R CMD INSTALL .
R CMD check --no-manual .In R:
testthat::test_local()If you add, remove, or upgrade dependencies, update the lockfile from R:
renv::settings$snapshot.type("explicit")
renv::status(dev = TRUE)
renv::snapshot(dev = TRUE)Please commit both code changes and the updated
renv.lock when dependency changes are intentional.
This repository includes two GitHub Actions workflows:
check-reproducible.yaml runs R CMD check
with pinned R 4.4.2 and renvcheck-latest.yaml runs broader checks across operating
systems and R versionsTogether, these workflows help keep the project reproducible for collaborators and stable for future users.