Skip to Content
Course content

28: Apply Family of Functions

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I see this mistake constantly, even from developers who have been using R for a while. They try to use apply() to quickly summarize a data frame, and suddenly their numbers vanish or they get a bunch of NA values without any clear error message. Let's look at a typical scenario.

# A simple dataset of employee data
employees <- data.frame(
  name = c("Alice", "Bob", "Charlie"),
  salary = c(70000, 80000, 90000),
  bonus = c(5000, 7000, 6000),
  stringsAsFactors = FALSE
)

# I want the average of the numeric columns
column_means <- apply(employees, 2, mean)
print(column_means)

If you run this, you'll likely see a warning about arguments not being numeric, and column_means will be a vector of NAs. Why? Because apply() is designed for matrices. When you pass a data frame to apply(), R coerces the entire thing into a matrix first. Since matrices must have a single data type, and you have a "name" column (strings), R converts every single value in the data frame to a string. You can't calculate the mean of the string "70000".

Stopping the Matrix Coercion Trap

The fix is simple: stop using apply() for data frames. Instead, use lapply() (list-apply) or sapply() (simplified-apply). Since a data frame is technically a list of columns, these functions treat each column as an individual element without forcing a type conversion across the whole table.

# This works because it treats columns as individual lists
means_list <- lapply(employees[, 2:3], mean)
print(means_list)

Now, lapply() always returns a list. That's great for consistency, but it's a pain to read. If you want a cleaner vector output, sapply() is your friend. It tries to "simplify" the result into the most intuitive data structure.

# Returns a named vector instead of a list
means_vector <- sapply(employees[, 2:3], mean)
print(means_vector)

Handling Grouped Data with tapply

Sometimes you don't want the mean of the whole column, but the mean per group. You could write a for-loop to filter the data frame for every unique category, but that's slow and verbose. This is where tapply() (table-apply) comes in. It takes a vector, a grouping factor, and a function.

# Let's add a department column
employees$dept <- c("IT", "HR", "IT")

# Calculate mean salary per department
dept_salaries <- tapply(employees$salary, employees$dept, mean)
print(dept_salaries)

I think of tapply() as the "group by" of the base R apply family. It's incredibly efficient for these kinds of summary tables.

The Swiss Army Knife: mapply

Finally, there's mapply(). While lapply() applies a function to one list, mapply() can apply a function to multiple lists simultaneously. It's a "multivariate" apply. It's less common, but it's a lifesaver when you have two different vectors that need to be passed into a function as separate arguments.

# A custom function that takes two inputs
calc_total_comp <- function(sal, bon) {
  return(sal + bon)
}

# Apply the function across two columns at once
total_comp <- mapply(calc_total_comp, employees$salary, employees$bonus)
print(total_comp)

Just a heads-up: as you get more comfortable with these, you'll notice that sapply() is convenient but can be dangerous in production code because its return type can change depending on the input data. If you're writing a script that must be robust, stick to lapply() and explicitly convert the result to a vector yourself.




📋 Practical Task

Processing Regional Weather Station Metrics

You have been given a data frame containing weather readings from three different stations. Your goal is to process this data without using any for loops.

weather_data <- data.frame(
  station = c("North", "North", "South", "South", "East", "East"),
  temp_c = c(12.5, 14.2, 22.1, 25.4, 18.0, 17.5),
  humidity = c(80, 85, 60, 55, 70, 72),
  wind_speed = c(10, 12, 5, 8, 15, 11)
)

Your Task:

  1. Use sapply() to calculate the mean of the three numeric columns (temp_c, humidity, and wind_speed).
  2. Use tapply() to find the average temp_c for each station.
  3. Create a custom function called heat_index_sim that takes temp and humidity as arguments and returns temp + (humidity / 10). Use mapply() to apply this function across the temperature and humidity columns to create a new vector of "Heat Index" values.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.