Chapter 4 Iteration and Grouped Operations
Iteration means applying a computation repeatedly. In R, the best choice may be vectorized arithmetic, a clear loop, or a member of the apply family. Choose the form that makes the input and output structure explicit.
4.1 Start with vectorization
Vectorized functions express many common operations directly.
values_to_scale <- c(2, 5, 8, 11)
(values_to_scale - mean(values_to_scale)) / sd(values_to_scale)
#> [1] -1.1618950 -0.3872983 0.3872983 1.1618950Vectorization is not a rule against loops. Use a loop when it communicates the algorithm more clearly or each iteration depends on previous state.
4.2 lapply() and vapply()
lapply() always returns a list. It works naturally with data frames because a
data frame is a list of equal-length columns.
sample_data <- data.frame(
units = c(5, 8, 6),
price = c(12.5, 11.0, 13.0),
region = c("north", "south", "west")
)
lapply(sample_data, class)
#> $units
#> [1] "numeric"
#>
#> $price
#> [1] "numeric"
#>
#> $region
#> [1] "character"vapply() requires an output template. It fails early if a result has an
unexpected type or length.
sapply() attempts to simplify automatically. It is convenient interactively,
but vapply() is safer when downstream code requires a stable contract.
4.3 Iterating over several inputs
Map() applies a function across inputs in parallel and returns a list.
mapply() uses similar logic and attempts to simplify.
4.4 Matrices and margins
apply(x, margin, fun) operates over matrix or array margins. A margin of 1
means rows and 2 means columns.
measurement_matrix <- matrix(1:12, nrow = 3, byrow = TRUE)
apply(measurement_matrix, 1, max)
#> [1] 4 8 12
apply(measurement_matrix, 2, mean)
#> [1] 5 6 7 8Prefer specialized functions such as rowSums(), rowMeans(), colSums(),
and colMeans() when they express the calculation directly.
4.5 Split–apply–combine
Many data-analysis tasks split observations into groups, apply a summary, and combine the results.
transactions <- data.frame(
segment = c("new", "new", "returning", "returning"),
revenue = c(25, 35, 60, 80)
)
by_segment <- split(transactions$revenue, transactions$segment)
vapply(by_segment, mean, numeric(1))
#> new returning
#> 30 70tapply() provides a compact form for a vector grouped by one or more factors.
aggregate() returns a data frame and is convenient when several grouping
columns must remain explicit.
4.6 Stateful iteration
When the next value depends on the previous value, a loop is usually clearer than forcing the problem into an apply function.
4.7 Interview checkpoints
- Compare
lapply(),sapply(), andvapply(). - Explain what the
MARGINargument means inapply(). - Describe split–apply–combine and name two R implementations.
- Explain when a
forloop is clearer than an apply-family function. - Explain why
rowMeans()is preferable toapply(x, 1, mean)when applicable.