contact@a2zlearners.com

1.5. SAS PROCEDURES -> Equivalent in R

1.5.5. SAS PROC TRANSPOSE and its equivalent in R using pivot_wider() and pivot_longer()

Input Data: sales_data

EMPLOYEE PRODUCT MONTH SALES
Alice Laptop Jan 5000
Alice Laptop Feb 5200
Alice Phone Jan 3000
Alice Phone Feb 3100
Bob Laptop Jan 4600
Bob Laptop Feb 4800
Bob Phone Jan 2800
Bob Phone Feb 2900

1 Objective A: Pivot PRODUCT values into columns (wide format)

We want:

EMPLOYEE MONTH Laptop Phone
Alice Jan 5000 3000
Alice Feb 5200 3100
Bob Jan 4600 2800
Bob Feb 4800 2900

SAS Code

proc sort data=sales_data; by employee month;

proc transpose data=sales_data out=wide_product;
  by employee month;
  id product;
  var sales;
run;

Explanation:

  • First, we sort by EMPLOYEE and MONTH because PROC TRANSPOSE’s BY requires sorted data.

  • id product: turns values in PRODUCT into column names.

  • var sales: fills the new columns with values from SALES.

R Code

# Dummy data for execution
library(dplyr)
library(tidyr)
sales_data <- tibble::tibble(
  EMPLOYEE = c("Alice", "Alice", "Alice", "Alice", "Bob", "Bob", "Bob", "Bob"),
  PRODUCT = c("Laptop", "Laptop", "Phone", "Phone", "Laptop", "Laptop", "Phone", "Phone"),
  MONTH = c("Jan", "Feb", "Jan", "Feb", "Jan", "Feb", "Jan", "Feb"),
  SALES = c(5000, 5200, 3000, 3100, 4600, 4800, 2800, 2900)
)
wide_product <- sales_data %>%
  pivot_wider(
    id_cols = c(EMPLOYEE, MONTH),
    names_from = PRODUCT,
    values_from = SALES
  )

Explanation:

  • id_cols: defines keys to stay in rows.

  • names_from: becomes column names (PRODUCT → Laptop, Phone).

  • values_from: fills in those columns using SALES values.

  • No sorting required!


2 Objective B: Reverse (wide → long format)

From the wide table above, convert back to original long form.

R Code

long_product <- wide_product %>%
  pivot_longer(
    cols = c(Laptop, Phone),
    names_to = "PRODUCT",
    values_to = "SALES"
  )

Explanation:

  • cols: selects which columns to gather.

  • names_to: stores column names in PRODUCT.

  • values_to: stores numbers in SALES.


3 Objective C: Add a prefix to transposed column names

EMPLOYEE MONTH SALE_Laptop SALE_Phone
Alice Jan 5000 3000
Bob Jan 4600 2800
wide_with_prefix <- sales_data %>%
  pivot_wider(
    id_cols = c(EMPLOYEE, MONTH),
    names_from = PRODUCT,
    values_from = SALES,
    names_prefix = "SALE_"
  )

Explanation:

  • Adds "SALE_" to every PRODUCT column name.

  • Useful for labeling metrics like SCORE_*, RATE_*, etc.


4 Advanced Explorations

1. Multiple Value Columns
EMPLOYEE PRODUCT SALES PROFIT
Alice Laptop 5000 1800
Alice Phone 3000 1200
# Dummy data for execution
sales_multi <- tibble::tibble(
  EMPLOYEE = c("Alice", "Alice"),
  PRODUCT = c("Laptop", "Phone"),
  SALES = c(5000, 3000),
  PROFIT = c(1800, 1200)
)
pivot_wider(
  data = sales_multi,
  id_cols = EMPLOYEE,
  names_from = PRODUCT,
  values_from = c(SALES, PROFIT)
)
EMPLOYEE SALES_Laptop SALES_Phone PROFIT_Laptop PROFIT_Phone
Alice 5000 3000 1800 1200

2. Use names_sep with Multi-Key Columns
pivot_wider(
  sales_data,
  id_cols = EMPLOYEE,
  names_from = c(PRODUCT, MONTH),
  values_from = SALES,
  names_sep = "_"
)

Output Columns: Laptop_Jan, Laptop_Feb, Phone_Jan, Phone_Feb


3. Use names_glue for Custom Naming
pivot_wider(
  sales_data,
  id_cols = EMPLOYEE,
  names_from = c(PRODUCT, MONTH),
  values_from = SALES,
  names_glue = "{PRODUCT}_SALES_{MONTH}"
)
EMPLOYEE Laptop_SALES_Jan Phone_SALES_Jan
Alice 5000 3000

4. Reverse wide → long format
pivot_longer(
  wide_product,
  cols = c(Laptop, Phone),
  names_to = "PRODUCT",
  values_to = "SALES"
)
EMPLOYEE MONTH PRODUCT SALES
Alice Jan Laptop 5000

5. Visualize Transposed Data
library(ggplot2)
ggplot(wide_product, aes(x = MONTH)) +
  geom_col(aes(y = Laptop, fill = EMPLOYEE), position = "dodge") +
  geom_col(aes(y = Phone, fill = EMPLOYEE), position = "dodge", alpha = 0.6)

Generates side-by-side bars for Laptop and Phone sales across employees and months.


**Summary Table**

Feature SAS: PROC TRANSPOSE R: pivot_wider() / pivot_longer()
Row → column (wide) ID, VAR pivot_wider()
Column → row (long) VAR pivot_longer()
Grouping key(s) BY (needs sorting) id_cols = ...
Multiple value columns One at a time, or merge later values_from = c("col1", "col2")
Custom column naming prefix=, delim= names_prefix=, names_sep=, names_glue=
Built-in flexibility Functional Extremely flexible
Reversibility Manual One-liners both directions

**Resource download links**

1.5.5.-SAS-PROC-TRANSPOSE-and-its-equivalent-in-R-using-pivot_wider-and-pivot_longer.zip