Lesson 11 / 25

Transforming Data with dplyr

Filter, select, mutate, summarise and group data with dplyr verbs.

A grammar of data manipulation

dplyr provides a small set of verbs that each do one thing and combine with the pipe. filter() keeps rows matching conditions; select() chooses columns (with helpers such as starts_with(), where(is.numeric)); mutate() adds or changes columns; arrange() sorts rows (desc() for descending); summarise() reduces rows to summary values; and group_by() makes subsequent verbs operate per group, so group_by(city) |> summarise(revenue = sum(total)) gives revenue per city. Newer syntax lets you group for a single operation with .by = city. Other useful verbs: count(), distinct(), rename(), slice_max(), relocate(), across() to apply the same function to many columns, and case_when() and if_else() inside mutate. Column names are used without quotes inside verbs (tidy evaluation). The same dplyr code runs on databases via dbplyr and on large data via arrow or duckplyr.

Answering business questions with dplyr

Each pipeline reads like a description of the analysis.

library(dplyr)

sales <- readr::read_rds("data/sales_clean.rds")

# revenue and order count per city, largest first
sales |>
  filter(!is.na(amount_inr)) |>
  summarise(
    orders = n(),
    revenue = sum(amount_inr),
    avg_order = mean(amount_inr),
    .by = city
  ) |>
  arrange(desc(revenue))

# monthly revenue with a size category
sales |>
  mutate(
    month = lubridate::floor_date(order_date, "month"),
    size = case_when(amount_inr >= 5000 ~ "large", amount_inr >= 1000 ~ "medium", .default = "small")
  ) |>
  count(month, size)

# top 3 orders per city
sales |>
  slice_max(amount_inr, n = 3, by = city)

# round every numeric column
sales |> mutate(across(where(is.numeric), \(x) round(x, 0)))

Instructions to a careful clerk

dplyr verbs are like instructions to a clerk with a ledger: "keep only paid orders, add a GST column, group by city, total them up, sort biggest first". Each instruction is simple; together they answer real questions.

Quick check: What does group_by(city) |> summarise(revenue = sum(total)) produce?

  • One row with total revenue
  • One row per city with that city's total revenue
  • The original rows sorted by city
  • A plot
Answer

One row per city with that city's total revenue — Grouping makes summarise produce one row per group.