contact@a2zlearners.com

1.5. SAS PROCEDURES -> Equivalent in R

1.5.7. SAS PROC PRINT and R Equivalents

This document walks through the core features of PROC PRINT in SAS and how to achieve the same behaviors in R—first covering the basics, then exploring advanced reporting tricks. Each section contains:

  • Concept: what you’re trying to do
  • SAS Code vs. R Code
  • Detailed Explanation of how each code works
  • Input Snapshot
  • Expected Output
  • Workflow: how it works

1. Print the Entire Data Set

**Concept**

List every column and every row in your data.

**SAS Code**

proc print data=sales_data;
run;

SAS Code Explanation

  • proc print invokes the PRINT procedure.
  • data=sales_data tells SAS which table to read (by default from the WORK library).
  • Without any var or subsetting options, PROC PRINT loops over all variables and all observations.
  • It sends the output to the open ODS destination (e.g., the listing or HTML).
  • run; finalizes and executes the step.

**R Code (base)**

# Dummy data for execution
library(dplyr)
sales_data <- tibble::tibble(
  Region = c("North", "North", "South", "South", "East", "East"),
  Month = c("Jan", "Feb", "Jan", "Feb", "Jan", "Feb"),
  Sales = c(1200, 1500, 900, 1100, 1300, 1400),
  Profit = c(200, 250, 100, 150, 300, 350),
  Category = c("A", "B", "A", "B", "A", "B")
)
sales_data           # or print(sales_data)

R Code Explanation

  • Typing the name of a data.frame or tibble in the console implicitly calls print().
  • For a base data.frame, print() displays every row and column (within console width).
  • For a tibble (from tibble/dplyr), printing shows the first 10 rows and all columns, plus a note about remaining rows/columns.

Input (sales_data)

Region Month Sales Profit Category
North Jan 1200 200 A
North Feb 1500 250 B
South Jan 900 100 A
South Feb 1100 150 B
East Jan 1300 300 A
East Feb 1400 350 B

Expected Output
All six rows and five columns are rendered.

Workflow

  1. SAS reads sales_data, streams records to PROC PRINT, and renders them.
  2. R evaluates the object, invokes print(), and displays the table.

2. Print Specific Variables

**Concept**

Show only the columns you care about.

**SAS Code**

proc print data=sales_data;
  var Region Sales;
run;

SAS Code Explanation

  • The var statement restricts PROC PRINT’s output to the listed variables (Region and Sales).
  • SAS builds an internal view of only those columns before printing.
  • Unlisted variables are completely omitted from the report.

**R Code (dplyr)**

library(dplyr)
sales_data %>%
  select(Region, Sales)

R Code Explanation

  • select(Region, Sales) constructs a new tibble containing only those two columns.
  • The pipe (%>%) passes the original sales_data into select().
  • Because the last call returns a tibble, the console prints it automatically.

Input (same as above)

Expected Output

Region Sales
North 1200
North 1500
South 900
South 1100
East 1300
East 1400

Workflow

  • SAS’s VAR selection happens inside PROC PRINT.
  • R’s select() removes unwanted columns before rendering.

3. Print the First N Observations

**Concept**

Limit output to the top *N* rows.

**SAS Code**

proc print data=sales_data(obs=3);
  var Region Sales;
run;

SAS Code Explanation

  • The data set option (obs=3) tells SAS to stop reading after the third observation.
  • Combined with var, only columns Region and Sales for the first three rows are printed.
  • Internally, SAS applies that row-limit filter during data set input.

**R Code (dplyr + head)**

sales_data %>%
  select(Region, Sales) %>%
  head(3)

R Code Explanation

  • select(Region, Sales) first reduces columns.
  • head(3) then returns only the first three rows of that result.
  • The console prints the returned tibble.

Expected Output

Region Sales
North 1200
North 1500
South 900

Workflow

  • SAS stops after row 3, then prints.
  • R chains column selection then row filtering.

4. Print the Last N Observations

**Concept**

Show the tail end of the table.

**SAS Code**

> **Note:** PROC PRINT has no built-in TAIL. You can use PROC SQL or a DATA step to filter by row number.
proc sql;
  select * from 
    (select *, monotonic() as _n_ from sales_data)
  having _n_ > (nobs-3);
quit;

SAS Code Explanation

  • monotonic() generates a row counter _n_.
  • nobs is a macro or automatic variable representing total rows.
  • The having clause keeps only those rows where _n_ is within the last three.
  • PROC SQL then prints the result.

**R Code (dplyr + tail)**

sales_data %>%
  select(Region, Sales) %>%
  tail(3)

R Code Explanation

  • select trims columns to Region and Sales.
  • tail(3) returns the last three rows of that data.
  • The tibble is printed to console.

Expected Output

Region Sales
South 1100
East 1300
East 1400

Workflow

  1. SAS builds a row‐numbered view and filters by last-three.
  2. R’s tail() automatically subsets the final rows.

5. Print a Range of Observations

**Concept**

Choose rows *M* through *N* (e.g., 4–6).

**SAS Code**

proc print data=sales_data(firstobs=4 obs=6);
  var Region Sales;
run;

SAS Code Explanation

  • firstobs=4 tells SAS to start at the fourth row.
  • obs=6 tells it to stop at the sixth.
  • Together they define a slice of the data set before printing.

**R Code (dplyr + slice)**

sales_data %>%
  select(Region, Sales) %>%
  slice(4:6)

R Code Explanation

  • slice(4:6) directly indexes rows 4, 5, and 6.
  • No prior filtering is needed; R returns exactly that subset.

Expected Output

Region Sales
South 1100
East 1300
East 1400

Workflow

  • SAS applies row bounds in the DATA step phase.
  • R indexes rows via slice().

6. Print Arbitrary Observations

**Concept**

Pick any set of row numbers (e.g., 2, 5, 6).

**SAS Code**

data want;
  set sales_data;
  if _n_ in (2,5,6);
run;

proc print data=want; 
run;

SAS Code Explanation

  • The DATA step reads sales_data row by row, with automatic counter _n_.
  • The if _n_ in (…) filter keeps only specified rows.
  • want is written, then PROC PRINT prints that smaller table.

**R Code (dplyr + slice)**

sales_data %>%
  select(Region, Sales) %>%
  slice(c(2, 5, 6))

R Code Explanation

  • slice(c(2, 5, 6)) tells dplyr exactly which rows to return.
  • Under the hood, it subsets the data frame by integer positions.

Expected Output

Region Sales
North 1500
East 1300
East 1400

Workflow

  • SAS filters via DATA step logic.
  • R directly indexes via slice().

7. Column-wise Totals

**Concept**

Append a grand-total row for numeric columns.

**SAS Code**

proc print data=sales_data noobs;
  var Sales Profit;
  sum Sales Profit;
run;

SAS Code Explanation

  • noobs suppresses the Obs column.
  • var Sales Profit selects only those two variables.
  • sum Sales Profit tells PROC PRINT to accumulate each column’s total as it reads rows.
  • At the end, PROC PRINT outputs a summary row with column sums.

**R Code (janitor)**

library(dplyr)
library(janitor)
sales_data %>%
  select(Sales, Profit) %>%
  adorn_totals("row")

R Code Explanation

  • adorn_totals("row") computes colSums() for numeric columns and appends that as a new row labeled “Total”.
  • Under the hood, janitor vets column types, sums, then uses bind_rows().

Input

Sales Profit
1200 200
1500 250
900 100

Expected Output

Sales Profit
1200 200
1500 250
900 100
3600 550

Workflow

  • SAS aggregates during the printing pass.
  • R post-processes with a separate function call.

8. Grouped Sections (BY-group Pages)

**Concept**

Print each level of a grouping variable in its own block.

**SAS Code**

proc sort data=sales_data; by Region; run;

proc print data=sales_data;
  by Region;
run;

SAS Code Explanation

  • proc sort orders the data by Region.
  • proc print … by Region; instructs PROC PRINT to start a new section (and page) for each distinct Region.
  • The BY statement adds a heading with the current group value above each block.

**R Code (dplyr + purrr)**

library(dplyr)
library(purrr)
sales_data %>%
  group_by(Region) %>%
  group_walk(~ print(.x))

R Code Explanation

  • group_by(Region) creates a grouped data frame keyed by Region.
  • group_walk(~ print(.x)) iterates over each group, passing the subset (.x) to the anonymous function which prints it.
  • Each print uses console defaults, so you see one block per region.

Input

Region Month Sales
East Jan 1300
West Feb 1600
East Feb 1400

Expected Output

East

Month Sales
Jan 1300
Feb 1400

West

Month Sales
Feb 1600

Workflow

  • SAS sorts then PRINT’s BY mechanism handles page breaks and headings.
  • R uses grouping and per-group printing in a loop.

9. Custom Formats and Labels

**Concept**

Display numbers or dates with custom formats and override column names.

**SAS Code**

proc print data=sales_data label noobs;
  var Sales Date;
  format Sales dollar8.2 Date monname.;
  label Sales="Net Revenue" Date="Month Name";
run;

SAS Code Explanation

  • label option enables custom column headers instead of variable names.
  • format assigns a numeric or date format to each variable at print time (e.g., dollar8.2 adds $ and two decimals, monname. outputs month names).
  • PROC PRINT applies these formats only for display; data remains unchanged.

**R Code (dplyr + scales)**

library(dplyr)
library(scales)
sales_data %>%
  transmute(
    `Net Revenue` = dollar(Sales),
    `Month Name`  = month.name[as.integer(factor(Month, levels = c("Jan", "Feb")))]
  )

R Code Explanation

  • transmute() both transforms and drops all other columns.
  • dollar() from scales formats numeric values to currency strings.
  • month.name[Date] uses R’s built-in vector of month names, indexing by the numeric Date value.
  • The result is a tibble of character columns ready for printing.

Input

Date Sales
1 1200
2 1500

Expected Output

Net Revenue Month Name
$1,200.00 January
$1,500.00 February

Workflow

  • SAS attaches display-only metadata (formats/labels).
  • R builds new formatted columns, so types change to character.

10. Using an ID Variable Instead of Obs#

**Concept**

Replace the default “Obs” column with a meaningful key.

**SAS Code**

proc print data=sales_data noobs;
  id OrderID;
  var Region Sales;
run;

SAS Code Explanation

  • noobs removes the automatic Obs column.
  • id OrderID; tells PROC PRINT to print OrderID in the left‐most column, aligning subsequent columns to the right.
  • The id variable is shown once per row in place of the row number.

**R Code (tibble)**

# Dummy data for execution
library(tibble)
sales_data <- tibble::tibble(
  OrderID = c("A1", "B2"),
  Region = c("North", "South"),
  Sales = c(1200, 900)
)
sales_data %>%
  column_to_rownames("OrderID") %>%
  print()

R Code Explanation

  • column_to_rownames("OrderID") transforms the OrderID column into row names.
  • When printing a data.frame with row names, R shows them in the left margin—functionally the same as SAS’s ID.

Input

OrderID Region Sales
A1 North 1200
B2 South 900

Expected Output

Region Sales
A1 North 1200
B2 South 900

Workflow

  • SAS uses the ID statement in PROC PRINT.
  • R manipulates row names before invoking print().

11. Styled HTML / PDF Tables

**Concept**

Produce publication-ready output with fonts, colors, and footnotes.

**SAS Code**

ods html file="report.html" style=Journal;
proc print data=sales_data; run;
ods html close;

SAS Code Explanation

  • ods html file=... style=Journal; opens an HTML ODS destination with a predefined style.
  • PROC PRINT writes its output into that HTML file, inheriting the style’s CSS.
  • ods html close; finalizes and closes the file.

**R Code (knitr + kableExtra)**

library(knitr)
library(kableExtra)
sales_data %>%
  kable("html", caption="Monthly Sales") %>%
  kable_styling(bootstrap_options=c("striped","hover"))

R Code Explanation

  • kable("html") converts the tibble into an HTML <table> string.
  • caption="Monthly Sales" adds a <caption>.
  • kable_styling() injects Bootstrap classes (striped, hover) for styling.
  • The result can be rendered in R Markdown to HTML or PDF.

Input
Same sales_data as above.

Expected Output
An HTML table with striped rows, hover highlights, and a caption.

Workflow

  • SAS wraps the PROC PRINT output in ODS markup and CSS.
  • R builds HTML and CSS classes via kable and kable_styling.

12. Interactive Web Tables (R Only)

**Concept**

Create sortable, filterable, paginated tables in a browser.

**R Code (DT)**

library(DT)
datatable(
  sales_data,
  options=list(pageLength=5, autoWidth=TRUE)
)

R Code Explanation

  • DT::datatable() takes any data.frame and turns it into an HTML widget.
  • Under the hood, it generates JavaScript (DataTables.js) plus JSON data.
  • Options like pageLength and autoWidth configure pagination and column sizing.
  • When viewed in an R Markdown document, Shiny app, or Jupyter notebook, you get interactive controls (search box, column sort, etc.).

Workflow
DT renders your data as an embedded interactive widget, enabling on-the-fly filtering and pagination.


**Resource download links**

1.5.7.-SAS-PROC-PRINT-and-R-Equivalents.zip