TempleCBE is an open-source clinical data science, biostatistical modeling, and pipeline orchestration framework developed for Temple University’s Center for Biostatistics and Epidemiology (CBE) at the Lewis Katz School of Medicine and College of Public Health.
TempleCBE bridges the critical methodology gap between classical regulatory biostatistics (SAS numerical parity, exact contingency inference, counting-process survival analysis), modern machine learning (tidymodels, penalized Cox regression, joint survival-status-time ensembles, Python reticulate export), and automated clinical pipeline orchestration (multi-table databases, Excel round-trips, DAG dependency tracking).
🎯 Which Gap Areas Does TempleCBE Cover?
Clinical research and biostatistical pipelines often face tooling fragmentation across language boundaries, regulatory standards, and modeling ecosystems. TempleCBE directly addresses six foundational gap areas:
| # | Methodology Gap Area | The Clinical & Modeling Problem | How TempleCBE Fills the Gap |
Dedicated Vignette |
|---|---|---|---|---|
| 1 | Start/Stop Counting-Process Data | Time-varying longitudinal covariates (Surv(tstart, tstop, status)) suffer interval leakage when events occur between scheduled visits; standard tools flatten or crash on counting-process matrices. |
tidy_tmerge_cox() constructs verified counting intervals; get_dataset_info() audits counting-process duration and events without matrix flattening; cv_coxnet() enforces subject-grouped partitioning to prevent cross-fold leakage. |
Nested Survival CV & SAS Survival |
| 2 | Tidymodels & Survival ML |
tidymodels and censored lack specialized clinical recipes (supervised likelihood encoding for survival, mixed-data FAMD) and calibrated multi-paradigm ensembles for complex clinical risk prediction. |
S3 hardhat engines (coxnet(), cv_coxnet()), custom recipe steps (step_lencode_coxnet(), step_famd()), a coxnet engine for parsnip::proportional_hazards() that also accepts start/stop outcomes, LOCO mini-patch inference (loco_mp_coxnet()), and stacked joint ensembles (joint_model()). |
Nested Survival CV |
| 3 | SAS Regulatory Parity & Validation | Migrating FDA/regulatory trials between SAS and R leads to discrepancies in PROC PHREG, PROC COMPARE, PROC PRINCOMP, zero-cell Fisher exact conservatism, and non-standard missing codes (999, -99). |
compare_df() gives a tidy cell-level comparison that agrees with SAS PROC COMPARE on a committed SAS 9.4 benchmark (differences are listed in ?compare_df); run_pca() reproduces exact PROC PRINCOMP eigenvalue tables; exact2x2() provides automatic mid-p exact testing; automated SAS macro bridges (run_sas_script()). |
R to SAS & PCA Analysis |
| 4 | Python & Reticulate Cross-Language ML | Advanced survival ML, SHAP explanations, and deep learning live in Python, while clinical data wrangling and biostatistical models live in R. | Seamless two-way reticulate serialization, exporting fitted R models, survival components, and data dictionaries directly into Python environments (DALEXtra, survex, scikit-learn). |
Reticulate Export |
| 5 | Multi-Table Clinical Databases & ER Graphs | Clinical datasets arrive as multi-table relational lists (inputs, ABG, Cardiovascular, survival_data). Managing consolidated dictionaries, Excel sheets, variable roles, and cohort overlap requires tedious boilerplate. |
Consolidated multi-table get_dataset_info.list(), multi-sheet Excel export/import (write_database_to_excel(), read_database_from_excel()), in-place metadata sync (apply_database_metadata()), variable role management (variable_roles()), and Entity-Relationship graph analysis (database_relationships(), cbe_database_venn()). |
EDA & Missingness |
| 6 | Pipeline DAGs & Reproducible Reporting | Multi-report analytical deliverables lack lightweight dependency tracking without configuring heavyweight workflow managers like Make or Snakemake. |
compute_graph() tracks script, data, and report dependencies as typed DAGs; as_tbl_graph() / as_igraph() converts to standard networks; render_pipeline() executes staleness-aware compilation of Quarto/Rmd deliverables. |
Compute Graph |
🏷️ Function Naming Convention (cbe_*)
TempleCBE follows a clear and consistent functional naming rule: - cbe_* is reserved for Temple CBE presentation and formatting only (themes, palettes, scales, plots, report tables, and number formatters such as cbe_theme_survival(), cbe_palette(), cbe_contingency_plot(), cbe_cox_table(), cbe_pformat()). - All other functions are plain verb-noun identifiers that directly describe their computational action (e.g. nested_survival_run(), cox_single(), checkpoint_map(), describe_columns(), drop_correlated_columns(), tune_alpha_by_split(), docx_review_extract()). - The legacy non-formatting cbe_* names (deprecated in 0.5.8) were removed in 0.7.0; find_deprecated_calls() finds them in your code.
📦 Installation
Install the development version directly from GitHub:
# Install pak if not already installed
if (!requireNamespace("pak", quietly = TRUE)) install.packages("pak")
# Install TempleCBE
pak::pak("jkylearmstrong/TempleCBE")Or via remotes:
remotes::install_github("jkylearmstrong/TempleCBE")🚀 Key Feature Showcases
1. Multi-Table Clinical Databases & Relational Linkage
Manage multi-domain clinical trial databases (e.g. baseline inputs, serial labs, and survival endpoints), compile unified data dictionaries, and evaluate entity-relationship linkages:
# 1. Define multi-table database list
clinical_db <- list(
inputs = data.frame(patient_id = 1:5, age = c(45, 52, 61, 39, 48), sex = c("M", "F", "M", "F", "M")),
ABG = data.frame(patient_id = c(1, 1, 2, 2, 3), ph = c(7.35, 7.40, 7.28, 7.32, 7.45)),
survival_data = data.frame(patient_id = 1:5, surv = Surv(c(10, 20, 30, 40, 50), c(1, 0, 1, 0, 1)))
)
# 2. Assign database metadata and dataset descriptions
database_name(clinical_db) <- "CardioPulmonaryTrial"
clinical_db <- set_dataset_labels(clinical_db, list(
inputs = "Baseline Demographics",
ABG = "Serial Arterial Blood Gas",
survival_data = "Time-to-Event Clinical Followup"
))
# 3. Consolidated data dictionary across all tables
get_dataset_info(clinical_db, subject_id = "patient_id")
# 4. Multi-sheet Excel workbook export with automated METADATA worksheet
write_database_to_excel(clinical_db, "Clinical_Trial_Database.xlsx")
# 5. Entity-Relationship graph & cohort overlap analysis
rel <- database_relationships(clinical_db)
as_tbl_graph(rel) # Convert directly to tidygraph
cbe_database_venn(clinical_db, id_col = "patient_id") # Visual Venn overlap2. Dataset Comparison (Checked Against SAS PROC COMPARE) & Visual Concordance
Audit dataset concordance down to the individual cell with tolerance-based matching and 2-set Venn visualizations. The counts and differences agree with SAS 9.4 PROC COMPARE (METHOD=ABSOLUTE) on the nine small comparisons of inst/sas/benchmark_proc_compare.sas; where they differ (the sign of a difference, variables of different types, trailing blanks, R classes against SAS types, attributes other than the type) is listed in ?compare_df:
df_base <- data.frame(id = 1:5, age = c(45, 52, 60, 65, 70), stage = c("I", "II", "II", "III", "IV"))
df_comp <- data.frame(id = 1:5, age = c(45, 52, 62, 65, 70), stage = c("I", "II", "II", "III", "IV"))
# Cell-level comparison, modelled on SAS PROC COMPARE
cmp <- compare_df(df_base, df_comp, by = "id", base_name = "Base", compare_name = "Audit")
print(cmp)
# Visual diagnostic: Observation and Variable Venn diagrams
autoplot(cmp, type = "observations")
autoplot(cmp, type = "discrepancies")3. Penalized Cox Models for Start/Stop & Longitudinal Data (tidymodels)
coxnet() and cv_coxnet() provide a tidymodels-native hardhat interface for regularized Cox regression with subject-grouped cross-validation. Outcomes can be right-censored, Surv(time, status), or start/stop counting-process data, Surv(tstart, tstop, status), for time-varying covariates:
lung_clean <- na.omit(lung[, c("time", "status", "age", "sex", "ph.ecog")])
# Fit elastic-net penalized Cox model
fit_cox <- coxnet(Surv(time, status) ~ ., data = lung_clean, penalty = 0.05, mixture = 0.5)
# Subject-grouped Cross-Validation with Integrated Brier Score
cv_fit <- cv_coxnet(Surv(time, status) ~ ., data = lung_clean, v = 5)
generics::tidy(cv_fit)
# Start/stop data (`long`: one row per subject-interval): folds keep each subject's intervals together
cv_ss <- cv_coxnet(
Surv(tstart, tstop, status) ~ x1 + x2, data = long,
subject_id = "subject_id", v = 5
)A penalty below the end of glmnet’s default path is honored (the path is continued down to it; penalty = 0 is the unpenalized fit) rather than silently clamped. coxnet is also registered as an engine of parsnip::proportional_hazards(), so it works in workflows and tune::tune_grid():
spec <- parsnip::proportional_hazards(penalty = 0.05, mixture = 0.5) |>
parsnip::set_engine("coxnet")
fit <- parsnip::fit(spec, Surv(time, status) ~ ., data = lung_clean)
predict(fit, lung_clean[1:3, ], type = "survival", eval_time = c(180, 365))4. Joint Survival-Status-Time Modeling
joint_model() fits penalized Cox proportional hazards, calibrated binary event classification, and follow-up duration regression together, and predicts all three side by side:
# Fit the multi-paradigm joint model
jm_fit <- joint_model(
lung_clean,
Surv(time, status) ~ age + sex + ph.ecog,
engine = "glmnet"
)
# Multi-horizon dynamic survival predictions
predict(jm_fit, lung_clean[1:5, ], eval_time = c(180, 365))5. Principal Component Analysis (SAS PROC PRINCOMP Parity)
run_pca() executes standardized PCA and outputs the exact eigenvalue variance table produced by SAS PROC PRINCOMP:
# Standardized PCA on continuous variables
iris_pca <- run_pca(iris[, 1:4], scale = TRUE)
# 1. Scree plot with Kaiser-Guttman threshold (Eigenvalue >= 1)
pca_scree_plot(iris_pca, metric = "eigenvalue", kaiser = TRUE)
# 2. Variable correlation circle on unit circle
pca_variables_plot(iris_pca, x = 1, y = 2)
# 3. Loadings biplot with 95% concentration ellipses
pca_biplot(iris_pca, group = iris$Species, ellipse = TRUE, percent = TRUE)6. Pipeline Dependency & Computational Graph Tracking
Model analysis scripts and data deliverables as an interactive DAG:
# Define pipeline stages and track downstream artifacts
graph <- compute_graph(
stages = list(
data_clean = list(inputs = "raw.csv", outputs = "clean.rds"),
model_fit = list(inputs = "clean.rds", outputs = "model.rds")
)
)
# Generate staleness-aware execution plan
get_render_plan(graph)📚 Comprehensive Vignettes
TempleCBE includes extensive vignettes covering theory, simulation, and clinical workflows:
| # | Vignette Title | Key Topics & Methodology |
|---|---|---|
| 01 | Exploratory Data Analysis, Missingness Auditing, and Normalization | Multi-code missing sentinels, missingness maps, IQR fences, and multi-table clinical database dictionaries. |
| 02 | Penalized Cox Models and Nested Cross-Validation | Start/stop counting process data, subject-level partitioning, step_lencode_coxnet, and yardstick survival scoring. |
| 03 | Visualizing Computational Pipeline Dependencies | Directed acyclic graphs (DAGs), multi-report orchestration, and reproducible analysis plans. |
| 04 | Validation Guide for SAS Users: Cox Models | Cross-validating cox_single(), cox_multi(), and tidy_tmerge_cox() against SAS PROC PHREG. |
| 05 | Cross-Validating Advanced Survival Models: R to SAS | Automated macro exports, macro validation suites, cbe_compare_df verification, and numerical concordance benchmarks. |
| 06 | Multi-Language Interoperability and Python Pipelines | Reticulate bridges, exporting survival matrices and models to Python (DALEXtra, survex), and cross-language artifact transfer. |
| 07 | Principal Component Analysis in R and SAS | SAS PROC PRINCOMP eigenvalue parity, Kaiser-Guttman scree plots, biplots, and clinical TAS dimension reduction. |
Access any vignette locally after installation via:
vignette("nested_survival_cv", package = "TempleCBE")🏛️ Ecosystem Architecture
TempleCBE serves as the public, auditable methodological layer of Temple University CBE’s clinical data science framework. Protected institutional studies and EHR analyses import TempleCBE to ensure statistical rigor while keeping confidential patient data secure:
-
pslongSim: Longitudinal propensity score simulation engine generating synthetic benchmark cohorts. -
omop-duck-db: High-performance OMOP Common Data Model querying with DuckDB. -
quarto_temple_brand: Official Temple University institutional Quarto document and slide deck templates.
🛡️ Rigorous Code Audit & v0.5.0 Release
In preparation for the v0.5.0 release, TempleCBE underwent an exhaustive, multi-tiered code and statistical audit addressing 137 verified findings across data privacy, numerical accuracy, cross-platform containment, and survival methodology:
- Data Privacy & De-Identification: Hardened identifier pseudonymization (the keyed HMAC methods now require a secret key and warn on short keys), synthetic investigator names sampled from the 250 most common US Census surnames and a pool of common first names, and automated redaction in multi-reviewer DOCX review tracking.
-
Statistical Integrity & Parity: Smoke tests on five classic cohorts from R’s
survivalpackage (veteran,lung,rotterdam,heart,colon) check that fits and predictions run and return well-formed output. SAS parity is checked against committed reference numbers printed by SAS 9.4 forPROC PHREG(the counting-process tumor data and thelungcohort),PROC PRINCOMP(the eigenvalue table ofrun_pca()oniris),PROC COMPARE(compare_df()on nine small comparisons) and the IPCW Brier score and integrated Brier score macro; re-running SAS itself is opt-in (TEMPLECBE_RUN_SAS_TESTS) and needs a SAS installation. -
Accelerated Racing Workflows: Integrated
finetuneANOVA and win-loss racing interfaces (control_race_survival(),tune_race_survival()) for fast hyperparameter optimization of penalized survival models and joint ensembles. -
Clean Canonical CBE API: Refactored core functions to canonical names (
km_single,cox_multi,compare_df, etc.) with full backwards-compatiblecbe_*aliases. -
Zero-Leakage Assurance: Before each release a private list of terms that must not appear is checked against every tracked file and the extracted text of tracked PDFs (
test-denylist.R; it runs only where that private list is available, so it is a release check, not part of CI).
👥 Authors & Contributors
-
J. Kyle Armstrong (
j.kyle.armstrong@temple.edu/@jkylearmstrong-temple) — Author, Creator, and Maintainer
-
Darina Chudnovskaya (
darina.c@temple.edu) — Contributor (PCA Analysis & Vignette Suite)
Lewis Katz School of Medicine at Temple University, Center for Biostatistics & Epidemiology
