Skip to Content
Course content

81: Vectorization vs Loops Performance

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

If you've spent any time in R forums or reading documentation, you've probably encountered the common refrain: "Loops are slow in R. Never use them; always vectorize." This has led many learners to believe that the for loop is some kind of forbidden syntax that will inevitably crash their system or take ten years to run if they dare to use it.

Let's get this out of the way: loops aren't "broken," and they aren't always the enemy. But in R, they are often the wrong tool for the job because of how the language handles memory and function calls. I've seen plenty of developers obsess over vectorizing code that only runs once a week on ten rows of data—don't be that person. However, when you're dealing with millions of observations, the difference isn't just a few seconds; it's the difference between a coffee break and a long weekend.

The Myth: "Loops are just slightly slower than vectors"

Many people think a loop is just a less elegant way of doing what a vector does. They assume the computer is doing the same amount of work, just in a different order. That's not actually what's happening. Let's look at a concrete example: squaring every number in a vector of one million elements.

# The Loop Approach
vec <- 1:1000000
result_loop <- numeric(length(vec))

system.time({
  for(i in 1:length(vec)) {
    result_loop[i] <- vec[i]^2
  }
})
# Typical result: ~0.3 to 0.5 seconds
# The Vectorized Approach
system.time({
  result_vec <- vec^2
})
# Typical result: ~0.005 to 0.01 seconds

The loop is orders of magnitude slower. Why? Because in the loop, R has to stop and ask itself a dozen questions for every single iteration: "What is the type of i? Where is vec in memory? Does result_loop have space at index i? Is the ^ operator applicable to these two types?" Doing that a million times creates a massive amount of overhead.

The Reality: Pushing the Heavy Lifting to C

When you use a vectorized operation like vec^2, you aren't actually telling R to run a loop in the R language. You are calling a highly optimized function written in C or Fortran. These languages are compiled, meaning they don't have to "ask questions" about data types a million times; they just blast through the memory addresses at near-hardware speed.

Vectorization is essentially the act of delegating the repetition to a lower-level language. When you write sum(x) instead of looping through x and adding to a total, you're handing the entire vector over to a C routine that knows exactly how to sum doubles in memory without the interpreter getting in the way.

But here is the nuance: you can't vectorize everything. If your current calculation depends on the result of the previous one (like a complex simulation or certain time-series models), a loop is often the only way. In those cases, the "trick" isn't to force vectorization, but to pre-allocate your memory—creating the empty vector numeric(length(vec)) before the loop starts—so R doesn't have to resize the object every time you add a new element.




📋 Practical Task

Exercise: Vectorizing a Weighted Sensor Calibration

You have been given a dataset of 500,000 raw sensor readings and a corresponding vector of calibration weights. Currently, the code uses a for loop to apply these weights and add a constant offset, which is making the data pipeline sluggish.

Your Goal: Rewrite the provided loop-based function into a fully vectorized version. You should observe a significant decrease in execution time.

# Setup data
set.seed(42)
readings <- rnorm(500000, mean = 100, sd = 15)
weights <- runif(500000, 0.9, 1.1)
offset <- 5.25

# The slow function
calibrate_sensors_loop <- function(r, w, o) {
  calibrated <- numeric(length(r))
  for(i in 1:length(r)) {
    calibrated[i] <- (r[i] * w[i]) + o
  }
  return(calibrated)
}

# TODO: Create calibrate_sensors_vectorized()
# Use the system.time() function to compare the performance of both.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.