SAS to R Migration for Clinical Teams
SAS licences are a six-figure line item; R is free, open and now demonstrably submission-capable — the FDA has reviewed fully R-based submission packages through the R Consortium pilots, and the pharmaverse packages used for ADaM and TLFs are built in the open by Roche, GSK, J&J and others. The question for most clinical teams is no longer whether R can do the work, but how to migrate without breaking a validated process. That “how” is what this page is about.
Planning a migration?
We run scoped pilot migrations: one study, parallel-run against your SAS outputs, with a written equivalence report your QA team can file. Ask for a free 20-minute scoping call — get in touch →.
The method
A risk-managed migration path
- Pilot on a closed study. Reproduce an already-delivered TLF package in R while the SAS originals stand as the reference. No live deliverable depends on the pilot.
- Parallel run & double programming. Every table is produced twice — R vs the SAS original — and compared programmatically. Differences are triaged: rounding conventions, tie-handling in nonparametric tests, variance defaults (Type III vs Type I sums of squares) account for most of them, and each gets a documented resolution.
- Validation documentation, not validation folklore. “Validated” describes your process: version-pinned package sets ({renv}), session information captured per run, package risk assessment ({riskmetric}), and QC logs. We deliver the templates and the evidence trail your SOPs need.
- Training on your own studies. Your programmers learn on your data and your shells — not toy examples — so the capability stays in-house after we leave. See our free R courses for the self-serve layer.
The dictionary
PROC ↔︎ R equivalence map
| SAS | R equivalent | Notes |
|---|---|---|
PROC FREQ |
janitor::tabyl(), gtsummary::tbl_summary(), chisq.test(), fisher.test() |
Row/column percents and tests in one table object |
PROC MEANS / PROC UNIVARIATE |
dplyr::summarise(), rstatix::get_summary_stats() |
Grouped stats via group_by() |
PROC TTEST |
t.test() |
Welch is the R default — match SAS with var.equal = TRUE |
PROC GLM / PROC ANOVA |
lm(), aov(), car::Anova(type = 3) |
SAS Type III sums of squares need car + effect coding |
PROC MIXED |
lme4::lmer(), nlme::lme(), mmrm::mmrm() |
{mmrm} reproduces the clinical MMRM with Kenward-Roger df |
PROC LIFETEST |
survival::survfit(), survdiff() |
Kaplan-Meier and log-rank |
PROC PHREG |
survival::coxph(ties = "efron") |
SAS default ties are Breslow — set explicitly when matching |
PROC LOGISTIC |
glm(family = binomial), gtsummary::tbl_regression(exponentiate = TRUE) |
ORs with profile-likelihood CIs |
PROC REPORT / PROC TABULATE |
rtables, gt, flextable |
Shell-faithful clinical layouts; export to RTF/DOCX |
PROC TRANSPOSE |
tidyr::pivot_longer() / pivot_wider() |
|
PROC SORT + DATA step |
dplyr::arrange(), mutate(), filter(), left_join() |
Joins replace MERGE with clearer semantics |
PROC IMPORT / PROC EXPORT |
haven::read_sas(), readr, writexl |
haven reads .sas7bdat directly — no export step needed |
| SAS macros | R functions + {purrr}, parameterised Quarto | Testable functions replace macro text substitution |
The traps in the Notes column — Welch vs pooled t, Type III sums of squares, Breslow vs Efron ties — are exactly where naive migrations “fail validation”. They are convention differences, not errors, and a parallel run surfaces every one of them.
See the trap live — in your browser
Real R via WebAssembly: the same t-test, two conventions. PROC TTEST’s pooled default vs R’s Welch default — edit and press Run Code:
Neither is “wrong” — but if the SAP says one and the code does the other, your parallel run fails. This is why the equivalence map exists.
Why now
The ecosystem has matured
- admiral — ADaM derivations as documented, testable R functions (pharmaverse).
- rtables & gtsummary — shell-faithful clinical tables, including RTF/DOCX delivery.
- FDA R-based submissions — the pilots that settled the “is R accepted?” question.
- TLF gallery — what the R outputs actually look like, next to their mock shells.
Start with one study
A pilot migration is a fixed-scope, fixed-quote engagement — and the equivalence report is yours to keep either way. Tell us about your stack →
Free R, Markdown & Quarto cheat sheets
One-page PDF guides — the “Which test?” decision chart, Markdown syntax, and Quarto reporting — free to download. Add your email for the occasional R tip too. No spam, unsubscribe anytime.