Translate SAS to R with AI, then prove the numbers match
The biggest trap with AI-translated code is that it runs but gives different numbers. This workflow forces a proof.
Facts on this page are checked against the sources linked here. The prompt has not yet been run on a live assistant. How we check.
Step 1: Translate
Translate the SAS program below to R. Prefer tidyverse and, where relevant, pharmaverse packages. Rules: 1. Preserve logic exactly. Do not "improve" it. 2. Add a comment above any line where SAS and R behave differently (missing values, sorting, rounding, merge/join semantics, formats, PROC MEANS defaults, PROC FREQ denominators). 3. List every assumption at the end. SAS CODE: [paste code - use public or simulated data only]
Step 2: Make the AI list the gotchas
List the 10 most common SAS-to-R discrepancies that would affect THIS program and tell me exactly how to test for each one.
Typical findings, with the specifics worth knowing:
- Rounding. SAS
ROUNDrounds halves away from zero (2.5 becomes 3). Base Rround()rounds to even (round(0.5)is 0,round(2.5)is 2), and because many decimals like 0.15 aren't stored exactly, R follows the stored value, not the printed one. SAS hasROUNDEfor round-half-to-even. Sources: SAS documentation, R-bloggers. - Quartiles and percentiles. SAS defaults to percentile definition 5 (
PCTLDEF=5), while R'squantile()defaults to type 7. A SAS blog comparison maps the SAS default to R'stype = 2, so usequantile(x, type = 2)to match SAS. Example from that post, with data 0, 1, 1, 1, 2, 2, 2, 4, 5, 8: the median is 2 under both, but the 75th percentile is 4 in SAS and 3.5 under R's default, and the 95th is 8 vs 6.65. The medians agree; the quartiles and tails are where programs disagree. Still run both on your own data before trusting a match. - Missing values. In SAS, a numeric missing value is smaller than any number and sorts first, so a test like
x < 1is true for missingx. In R, comparisons withNAreturnNA, notTRUEorFALSE. Filters that "worked" in SAS can silently drop or keep different rows. - Merges vs joins. A SAS DATA step match-merge is not an SQL join, and behaves differently when BY values repeat in more than one dataset. SAS writes a "repeats of BY values" note to the log, which experienced SAS programmers treat as a sign of a data problem, not a routine message. dplyr (1.1.0 and later) warns on many-to-many joins. Compare row counts after every merge.
- Sorting and character case. Check default sort order and case sensitivity on character keys.
Step 3: Prove it
Run both programs on the same public dataset and compare. Good free sources are the original CDISC pilot data in the phuse-org/phuse-scripts GitHub repository (see the repository: SDTM is under data/sdtm/cdiscpilot01, ADaM under data/adam/cdisc, and there are also updated pilot sets; folder layouts can change) and the pharmaverse R packages pharmaversesdtm and pharmaverseadam, which ship SDTM and ADaM test data built from the pilot study. Then compare:
- Row counts match
- Key summary statistics match to the digits you report
- Edge cases checked: missing values, ties, zero counts
Write R code that compares my SAS output (exported to CSV) with my R output and reports every difference with variable, row, and magnitude.