sas_r_map.RdThe mapping a SAS programmer actually needs when moving a study to R: for
each SAS macro, PROC or DATA-step idiom, the R call that replaces it and –
the column that matters – one line on where the two behave differently.
A mapping that claims equivalence where behaviour diverges is worse than no
mapping, so difference is populated for every row and is the reason the
table exists.
sas_r_mapA tibble::tibble() with 51 rows and 8 columns:
Grouping: "display" for this package's own tables, then
"counting", "summary stats", "data handling", "strings",
"formats", "metadata", "macro language", "output", "input".
Short key for the SAS macro/PROC/DATA-step idiom.
The idiom written out in full.
The R call that replaces it.
Where the two behave differently. Never empty.
The sasparity export covering this row, or NA.
Number of PHUSE .sas files containing the idiom.
Path of one such file, relative to the corpus root.
PhUSE phuse-scripts and TestDataFactory repositories, MIT
licence. Rebuild with data-raw/sas_r_map.R.
Query it with parity_note() rather than by name if you want filtering.
The SAS side is taken from two public, MIT-licensed PhUSE repositories:
phuse-org/phuse-scripts (lang/SAS/, contributed/) and
phuse-org/TestDataFactory (Code/) – 75 .sas files in total. Every
row is evidence-backed: data-raw/sas_r_map.R re-scans that corpus and
refuses to write this dataset unless each idiom is found in at least one
published SAS program. phuse_files is the number of files the idiom
appears in and phuse_example names one of them. No PHUSE source code is
redistributed in this package; only paths and counts are.
The six rows with a non-NA sasparity_fn are this package's own
displays. Their sas_equivalent names a sponsor-style macro
(%demog, %aesumm, ...): those macro names are the conventional
industry ones and are illustrative, not PHUSE artefacts – it is the PROC
idiom in the same string, and the file in phuse_example, that the corpus
evidences.
The difference column is a one-line warning, not a validation statement.
It tells you where to look; it does not prove numerical equivalence for
your study, and no row asserts that the R call reproduces SAS output
bit-for-bit. Rows outside topic == "display" map to packages this one
does not depend on (tidyr, haven, xportr, mmrm,
survival, r2rtf, ...); they are documentation, not a runtime
contract, and nothing in sasparity calls them.
nrow(sas_r_map)
#> [1] 51
subset(sas_r_map, topic == "counting", c(sas_idiom, r_function))
#> # A tibble: 5 × 2
#> sas_idiom r_function
#> <chr> <chr>
#> 1 _N_ / monotonic() row counter dplyr::row_number()
#> 2 DATA step FIRST. / LAST. BY-group flags dplyr::group_by() + dplyr::slice_head…
#> 3 PROC FREQ TABLES a*b dplyr::count() / tern::count_occurren…
#> 4 PROC SORT NODUPKEY dplyr::distinct()
#> 5 PROC SQL count(distinct usubjid) dplyr::n_distinct()
# the differences are the point of the table
sas_r_map$difference[sas_r_map$sas_idiom == "PROC SORT NODUPKEY"]
#> [1] "NODUPKEY sorts first, keeps the first record per key and can write the rest to DUPOUT= for review; distinct() keeps the first row in the current row order and discards the duplicates with no record of what was dropped."