Clinical research statistics, as tidy data. clinstats covers the analyses
that recur in clinical and translational papers — discrimination, odds
ratios, univariable and multivariable regression tables, survival cut points,
and expression-matrix preparation — and returns a tibble from every function
so results can be printed, filtered, joined, and exported.
The package also ships curated colorectal cancer clinical datasets assembled from public repositories, and a Quarto analysis report template.
library(clinstats)
cox_table(
clin_crc,
time = "rfs.delay",
event = "rfs.event",
factors = c("sex", "age", "tnm.stage")
)
#> # A tibble: 3 × 13
#> term variable level n n_event hr_univariable univ_ci_lower
#> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
#> 1 sexM sex M 1641 561 1.14 0.967
#> 2 age age <NA> 1640 561 0.999 0.993
#> 3 tnm.stage tnm.stage <NA> 1632 558 1.82 1.62
#> # ℹ 6 more variables: univ_ci_upper <dbl>, univ_p <dbl>,
#> # hr_multivariable <dbl>, multi_ci_lower <dbl>, multi_ci_upper <dbl>,
#> # multi_p <dbl>
Clinical statistics code tends to be written once per paper and copied forward. The same ROC summary, the same two regression tables, the same expression cleanup, reimplemented slightly differently each time — which makes results hard to reproduce and easy to get subtly wrong.
clinstats collects those analyses into tested functions. Three properties
do the work:
The statistical routines were rewritten from the retired gaofenglib
package, and the datasets carried over unchanged from
curatedClinicalData. See Compatibility for the migration
table.
Prebuilt binaries for Linux, macOS, and Windows come from r-universe, so no compiler is needed:
install.packages(
"clinstats",
repos = c(gflab = "https://gflab.r-universe.dev", CRAN = "https://cloud.r-project.org")
)
Installing from source through GitHub also works:
# install.packages("remotes")
remotes::install_github("gflab/clinstats")
R 4.1 or later is required.
| Area | Functions |
|---|---|
| Discrimination |
roc_summary(), odds_ratio()
|
| Regression tables |
cox_table(), logistic_table(), evaluate_model()
|
| Survival analysis |
survival_cutoff(), survival_response(), resample_cox()
|
| Expression data |
clean_expression(), oncotype_crc()
|
| TCGA clinical data | tcga_clinical() |
| Reporting | copy_report_template() |
marker <- scale(clin_crc$age)
roc_summary(marker, clin_crc$rfs.event)
#> # A tibble: 1 × 12
#> n n_event auc auc_ci_lower auc_ci_upper direction threshold
#> <int> <int> <dbl> <dbl> <dbl> <chr> <dbl>
#> 1 1698 574 0.514 0.485 0.542 > 0.143
odds_ratio(marker, clin_crc$rfs.event)
roc_summary() returns the area under the curve, its confidence interval,
the optimal operating point, and the sensitivity and specificity at that
point. direction = "auto" lets pROC choose the orientation from the data,
which is what you want when the sign of a marker is not known in advance.
cox_table() and logistic_table() fit every variable on its own, fit one
multivariable model, and return both sets of estimates in a single table.
Numeric variables contribute one row; factors contribute one row per level
against the reference level.
cox_table(
clin_crc,
time = "rfs.delay",
event = "rfs.event",
factors = c("sex", "age", "tnm.stage", "cms")
)
The multivariable model includes every requested variable by default. Use
multivariable = "significant" to keep only variables with a univariable
likelihood-ratio p-value below 0.05, or multivariable = "none" for
univariable estimates alone.
evaluate_model(train, test, outcome ~ marker1 + marker2)
Returns the training and test AUC with confidence intervals and a DeLong comparison between them.
cleaned <- clean_expression(expression) # samples in rows, genes in columns
oncotype_crc(cleaned) # composes directly
clean_expression() drops unusable columns, expands " /// "
multi-mappings, optionally maps identifiers with org.Hs.eg.db, and
collapses duplicated gene columns to the probe with the largest median
absolute deviation.
clin_crc, clin_crc_gf, and clin_crc_cell hold clinical annotations for
2,816 to 2,868 colorectal cancer samples across 25 columns: demographics, TNM
stage and T/N/M categories, tumour location and grade, adjuvant chemotherapy,
relapse-free, overall, and disease-free survival with their times,
MMR/CIMP/CIN status, TP53/KRAS/BRAF mutation status, source dataset, and
consensus molecular subtype.
Sources are the GEO series GSE14333, GSE17538, GSE18088, GSE26906, GSE31595, GSE33113, GSE37892, GSE39084, and GSE39582 (the PETACC-3 cohort), plus TCGA clinical exports. Every source is public and the data contain no patient identifiers.
dim(clin_crc) # 2816 x 25
table(clin_crc$dataset)
?clin_crc documents the column layout; data-raw/README.md records the
source of each cohort and the SHA-256 of each released object. Biological and
clinical conclusions drawn from these datasets remain the responsibility of
the analyst.
copy_report_template() writes a Quarto document into the current project,
with settings for HTML and PDF output and example chunks that use the bundled
datasets.
copy_report_template()
clinstats is the maintained successor of the archived gaofenglib and
curatedClinicalData repositories. Those packages still install, and
clinstats consolidates them so the lab maintains one package rather than
several overlapping ones.
| Old | New |
|---|---|
calc_logit() |
roc_summary() |
calc_or() |
odds_ratio() |
factor_analysis_cox() |
cox_table() |
factor_analysis_logit() |
logistic_table() |
eval_logit() |
evaluate_model() |
calc_cutoff_survivalroc() |
survival_cutoff() |
calc_resamp_cox() |
resample_cox() |
clean_dat() |
clean_expression() |
calc_oncotypedx_crc() |
oncotype_crc() |
extract_tcga_clinical() |
tcga_clinical() |
get_survival() |
survival_response() |
clin_crc, clin_crc_gf, clin_crc_cell
|
same names |
Changes to expect when migrating:
rownames() no longer apply.multivariable = "significant" to reproduce the previous
univariable-screening rule.survival_cutoff() computes the Kaplan-Meier Youden index with the
survival package, so the long-unmaintained survivalROC is no longer a
dependency.resample_cox() reports per-marker selection frequencies instead of a
raw p-value matrix, and follows the future parallel plan.init_R() and update_all() were removed. A library should not
reinstall the user's environment.gfplot produces the figures that go with
these analyses — Kaplan-Meier curves with hazard ratios, ROC curves, risk
score distributions — in the lab house style. The two packages share the same
datasets, so clinstats results feed directly into gfplot figures.
citation("clinstats")
See CITATION.cff for machine-readable metadata. Release v0.1.2 is
available as a tag, so a specific state can be pinned.
Bug reports and feature requests are welcome through GitHub Issues. Reference documentation for every function is on the package site.
Apache License 2.0. See LICENSE.md. Copyright 2026 FengGao Lab contributors.