How to convert wide format to long format in R
· 2 min read · Updated March 14, 2026 · beginner
r reshaping tidyr data.table tidyverse
Converting wide data to long format is a common data transformation. Here is how to do it with the major approaches.
With tidyr (tidyverse)
The tidyverse approach uses pivot_longer():
library(tidyr)
# Simple case: specify columns to gather
long_df <- wide_df %>%
pivot_longer(cols = c(q1, q2, q3, q4),
names_to = "quarter",
values_to = "sales")
The cols argument identifies which columns become values. Use column selection helpers:
library(tidyr)
library(dplyr)
# Select all columns from q1 to q4
long_df <- wide_df %>%
pivot_longer(cols = q1:q4,
names_to = "quarter",
values_to = "sales")
# Select columns by pattern
long_df <- wide_df %>%
pivot_longer(cols = starts_with("q"),
names_to = "quarter",
values_to = "sales")
With data.table
The data.table package is extremely fast for large data sets:
library(data.table)
dt <- as.data.table(wide_df)
# Melt from wide to long
long_dt <- melt(dt,
id.vars = "id",
measure.vars = c("q1", "q2", "q3", "q4"),
variable.name = "quarter",
value.name = "sales")
Use patterns for flexible column selection:
long_dt <- melt(dt,
id.vars = "id",
measure.vars = patterns("^q"),
variable.name = "quarter",
value.name = "sales")
With base R
Base R can reshape with reshape():
# Wide to long using base reshape()
long_df <- reshape(wide_df,
direction = "long",
varying = list(c("q1", "q2", "q3", "q4")),
v.names = "sales",
timevar = "quarter",
times = c("q1", "q2", "q3", "q4"))
This is more verbose but works without any packages.
Common Options
| Option | tidyr | data.table | Purpose |
|---|---|---|---|
| ID columns | id.vars | id.vars | Columns to keep as identifiers |
| Value columns | cols | measure.vars | Columns to reshape |
| Names output | names_to | variable.name | Name for column with old column names |
| Values output | values_to | value.name | Name for column with cell values |
Handling Multiple Value Columns
When you have multiple value columns (e.g., revenue and profit for each quarter):
library(tidyr)
long_df <- wide_df %>%
pivot_longer(cols = c(revenue_q1, revenue_q2, profit_q1, profit_q2),
names_to = c(".value", "quarter"),
names_sep = "_")
This creates separate columns for revenue and profit.
See Also
- tidyr::pivot_longer() / tidyr::pivot_wider() — Full reference for tidyr pivoting
- Reshaping Data with tidyr — Complete guide to tidyr reshaping