The apply Family
Prerequisites: Functions, Lists
The apply family of base R functions runs a function on each element
of a vector, list, or matrix, and collects the results — replacing many
for loops.
lapply and sapply
words <- c("apple", "banana", "kiwi")
lapply(words, nchar)
sapply(words, nchar)
sapply(1:3, \(n) n^2)
[[1]]
[1] 5
[[2]]
[1] 6
[[3]]
[1] 4
apple banana kiwi
5 6 4
[1] 1 4 9
lapplyalways returns a list — one element per input.sapplysimplifies the result to a vector when it can (and uses the input as names when the input is text).
vapply — safer in functions
sapply can return different types depending on the input, which causes
surprises inside functions. vapply states the expected result type:
vapply(c("apple", "kiwi"), nchar, FUN.VALUE = integer(1))
apple kiwi
5 4
Applying over data frame columns
A data frame is a list of columns, so sapply works on columns:
df <- data.frame(a = c(1, 2, 3), b = c(10, 20, 30))
sapply(df, mean)
a b
2 20
apply for matrices, and mapply for several inputs
m <- matrix(1:6, nrow = 2)
apply(m, 1, sum)
apply(m, 2, max)
mapply(\(x, y) x * y, 1:3, 4:6)
[1] 9 12
[1] 2 4 6
[1] 4 10 18
apply(m, 1, ...) works row by row; apply(m, 2, ...) column by column.
Don't forget vectorization
Before reaching for sapply(x, \(v) v * 2), check whether a vectorized
expression does the job: x * 2. The apply family is for functions that
genuinely have to run once per element.