R tidyr Reshape Data
tidyr reshapes data between wide format (many columns) and long format (many rows). Most visualization and statistical functions in R prefer long format. Most human-readable data arrives in wide format. tidyr's two main functions — pivot_longer() and pivot_wider() — convert between these formats.
Wide vs Long Format
WIDE FORMAT (human-friendly): Student Math Science English Asha 85 90 78 Balu 72 80 88 Cena 91 85 92 LONG FORMAT (R-friendly for analysis): Student Subject Score Asha Math 85 Asha Science 90 Asha English 78 Balu Math 72 Balu Science 80 Balu English 88 Cena Math 91 ...
pivot_longer() — Wide to Long
library(tidyr)
library(dplyr)
wide <- data.frame(
student = c("Asha","Balu","Cena"),
Math = c(85, 72, 91),
Science = c(90, 80, 85),
English = c(78, 88, 92)
)
long <- pivot_longer(
wide,
cols = c(Math, Science, English), # columns to collapse
names_to = "subject", # new column for old column names
values_to = "score" # new column for values
)
print(long)
# student subject score
# 1 Asha Math 85
# 2 Asha Science 90
# 3 Asha English 78
# 4 Balu Math 72
# ...
pivot_longer() with cols Helpers
# Select columns to pivot using helpers
pivot_longer(wide, cols=-student, names_to="subject", values_to="score")
pivot_longer(wide, cols=starts_with("M"), names_to="subject", values_to="score")
pivot_longer(wide, cols=2:4, names_to="subject", values_to="score")
pivot_wider() — Long to Wide
# Reverse: go from long back to wide wide_again <- pivot_wider( long, names_from = "subject", # column whose values become column names values_from = "score" # column whose values fill the table ) print(wide_again) # student Math Science English # Asha 85 90 78 # Balu 72 80 88 # Cena 91 85 92
separate() — Split One Column Into Two
df <- data.frame(
full_name = c("Asha Sharma", "Balu Kumar", "Cena Patel"),
dob = c("1995-08-15", "1992-03-22", "1998-11-05")
)
df |>
separate(full_name, into=c("first","last"), sep=" ") |>
separate(dob, into=c("year","month","day"), sep="-")
# first last year month day
# 1 Asha Sharma 1995 08 15
# 2 Balu Kumar 1992 03 22
# 3 Cena Patel 1998 11 05
unite() — Combine Two Columns Into One
df2 <- data.frame(
first = c("Asha","Balu"),
last = c("Sharma","Kumar"),
year = c(2024, 2024),
month = c(8, 9)
)
df2 |>
unite("full_name", first, last, sep=" ") |>
unite("period", year, month, sep="-")
fill() — Fill Missing Values Downward
df3 <- data.frame(
month = c("Jan", NA, NA, "Feb", NA),
sales = c(1000, 1200, 800, 1500, 900)
)
fill(df3, month, .direction="down")
# month sales
# 1 Jan 1000
# 2 Jan 1200
# 3 Jan 800
# 4 Feb 1500
# 5 Feb 900
drop_na() and replace_na()
df4 <- data.frame(x=c(1,NA,3), y=c("a",NA,"c"))
drop_na(df4) # remove rows with any NA
replace_na(df4, list(x=0, y="unknown")) # fill NAs
Data reshaping is often the most time-consuming part of a data project. pivot_longer() and pivot_wider() handle 90% of reshape tasks. separate() and unite() handle the column splitting and joining that clean messy composite fields. Together, these tools get your data into whatever shape a function or visualization needs.
