Unit 04.02: Six verbs, and which of them change the shape
Six verbs cover the large majority of everyday analysis. The skill is knowing which one changes the shape of the table.
Which verb changes what
select() chooses columns. filter() chooses rows. mutate() adds a column and leaves the row count alone. arrange() reorders rows and changes nothing else.
group_by() plus summarise() is the pair that changes the grain. group_by() marks how the rows should be split, and summarise() collapses each group to a single row. The table that comes out has a different meaning per row from the one that went in, which is why row counts before and after are worth printing.
.groups = 'drop' at the end of summarise() removes the grouping. Without it the result stays grouped, and the *next* verb silently operates within groups.
This block runs all six on one table, in the order you usually want them.
suppressPackageStartupMessages(library(dplyr))
ward_visits <- data.frame(
ward = c("North", "North", "South", "South", "East", "East"),
month = c("Jan", "Feb", "Jan", "Feb", "Jan", "Feb"),
visits = c(412, 455, 388, 401, 502, 498),
residents = c(12400, 12400, 9800, 9800, 15100, 15100),
notes = c("", "", "short staffed", "", "", "system down")
)
report <- ward_visits |>
select(ward, month, visits, residents) |> # columns you will use
filter(visits > 390) |> # rows you will keep
mutate(per_1000 = round(visits / residents * 1000, 1)) |> # new columns
group_by(ward) |> # the grain of the answer
summarise(months = n(),
mean_per_1000 = round(mean(per_1000), 1),
.groups = "drop") |> # back to one row per ward
arrange(desc(mean_per_1000)) # the order a reader reads
print(report)
cat("\nRows: ", nrow(ward_visits), " in, ", nrow(report), " out.\n", sep = "")
cat("Verbs in order: select, filter, mutate, group_by, summarise, arrange.\n")
Six input rows become three output rows, one per ward. South comes top at 40.9 mean visits per 1000 residents from a single month — the filter removed its other row — with North at 35 and East at 33.1. Note that South ranks first on one month of data: the months column is there precisely so a reader can see that before quoting the ranking.
The mistake this prevents
The mistake is forgetting .groups = 'drop' and then calling mutate(), which now computes within each group rather than across the table. The numbers are wrong and nothing warns you.
Takeaway
Use select and filter to shrink early, mutate to derive, and group_by with summarise to change the grain deliberately. Print the row count either side of a summarise, and drop the grouping when you are done with it.
