The 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_map

Format

A tibble::tibble() with 51 rows and 8 columns:

topic

Grouping: "display" for this package's own tables, then "counting", "summary stats", "data handling", "strings", "formats", "metadata", "macro language", "output", "input".

sas_idiom

Short key for the SAS macro/PROC/DATA-step idiom.

sas_equivalent

The idiom written out in full.

r_function

The R call that replaces it.

difference

Where the two behave differently. Never empty.

sasparity_fn

The sasparity export covering this row, or NA.

phuse_files

Number of PHUSE .sas files containing the idiom.

phuse_example

Path of one such file, relative to the corpus root.

Source

PhUSE phuse-scripts and TestDataFactory repositories, MIT licence. Rebuild with data-raw/sas_r_map.R.

Details

Query it with parity_note() rather than by name if you want filtering.

Provenance

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.

Limits

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.

Examples

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."