Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Functions  ›  Capstone Project

The apply Family

Apply Family 15 minThe apply functions run a function on every piece of a list, vector, matrix or group, and their first letter hints at the result: lapply gives a list, sapply and vapply a vector, apply works over rows or columns, tapply per group.

The apply Family

You now have the garden's data as a list of pickings per plot, a weekly matrix and a data frame. The questions are all the same shape: "do this to every plot", "total every row", "sum per crop". Writing a loop for each works, but R has a family of functions that each do one of these jobs in a single line.

The rule

Give a function to every piece; the name tells you the shape back.

Each member takes some data, splits it into pieces, runs a function on every piece and combines the results. They differ in what they walk over and what they give back.

weighings <- list(A = c(5, 4, 3.5), B = c(3, 5), C = c(7, 8))

lapply(weighings, sum)                 # a list: $A 12.5, $B 8, $C 15
sapply(weighings, sum)                 # a vector: A 12.5, B 8, C 15
vapply(weighings, sum, numeric(1))     # a vector, type guaranteed
vapply(weighings, length, integer(1))  # A 3, B 2, C 2
  • lapply(x, f): list. Always returns a list, one item per piece.
  • sapply(x, f): simplify. Tries to turn that list into a vector or matrix. Handy at the console, but the result's shape depends on the data.
  • vapply(x, f, template): like sapply, but you declare what each result must be, such as numeric(1) for "one number". If any piece breaks the promise you get an error, not a surprise. Prefer it inside functions.

For grids and groups:

m <- matrix(c(5, 3, 7, 7.5, 5, 8), nrow = 3,
            dimnames = list(c("A", "B", "C"), c("wk1", "wk2")))
apply(m, 1, sum)    # rows:    A 12.5, B 8, C 15
apply(m, 2, sum)    # columns: wk1 15, wk2 20.5

harvest <- data.frame(crop = c("tomato", "bean", "tomato", "chilli", "bean"),
                      kg   = c(12.5, 8, 15, 3.5, 6))
tapply(harvest$kg, harvest$crop, sum)   # bean 14, chilli 3.5, tomato 27.5
  • apply(m, MARGIN, f): over the rows (1) or columns (2) of a matrix.
  • tapply(values, groups, f): splits values by groups and applies f to each group, the same kind of "per group" summary as SQL's GROUP BY.

Short functions can be written inline: sapply(weighings, function(w) max(w)), or with R 4.1's shorthand \(w) max(w), gives A 5, B 5, C 8. For walking over two vectors side by side, mapply() and Map() exist too.

These functions are not magic speed-ups over a well-written loop. Their value is clarity: one line that states "sum every piece" leaves less room for bookkeeping mistakes.

The shortcut

Pick by what you are walking over and what you want back:

  • A list or vector, want a list: lapply.
  • A list or vector, want a plain vector: vapply (or sapply at the console).
  • The rows or columns of a matrix: apply with 1 or 2.
  • Values split by a grouping column: tapply.
tapply(harvest$kg, harvest$crop, sum)Step 1 of 3
  1. Split

    Group the weights by crop: bean gets 8 and 6, chilli gets 3.5, tomato gets 12.5 and 15.

Drills

Answer fast — trust the rule.

quick drill

What is class(lapply(weighings, sum))?

quick drill

Ignoring names, what does sapply(weighings, length) return?

quick drill

For the weekly matrix m, what does apply(m, 2, sum) return?

quick drill

What does tapply(harvest$kg, harvest$crop, max) give for tomato?

quick drill

Which call guarantees one number per piece, or an error?

Remember

  • Give a function to every piece; the name tells you the shape back.
  • Shortcut: list back, lapply; vector back, vapply; rows or columns, apply; per group, tapply.
  • Trap: trusting sapply's guess about the shape inside code that must not break.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainPick the right apply

For the garden data, name the apply function you would use and write the call for: (1) the total of each plot's weighings as a plain numeric vector, (2) the total of each row of the weekly matrix m, (3) the total kg per crop from harvest. Explain each choice.