
Image by Editor | Midjourney
Vectorization in R applies operations to entire datasets and avoids explicit loops. This makes computations faster and more efficient. R’s optimized functions handle data in bulk. Instead of processing elements one by one, vectorized functions work on the whole dataset. This reduces execution time and improves readability. R is designed for vectorized operations. Understanding vectorization helps write high-performance R code. This article will explore vectorization in R.
Basic Arithmetic Operations
In R, arithmetic operations are vectorized. They work on entire vectors without loops. Operations like addition, subtraction, multiplication, and division run efficiently.
- +, -, *, / – Basic arithmetic operations
- sum(x), prod(x) – Sum and product of elements
- mean(x), median(x), sd(x), var(x) – Mean, median, standard deviation, and variance
# Define two vectors
a <- c(1, 2, 3, 4, 5)
b <- c(10, 20, 30, 40, 50)
# Loop-based addition
normal_time <- system.time({
c_loop <- numeric(length(a))
for (i in seq_along(a)) {
c_loop[i] <- a[i] + b[i]
}
})
print("Loop-based result:")
print(c_loop)
print(paste("Loop-based time (seconds):", normal_time["elapsed"]))
# Vectorized addition
vector_time <- system.time({
c <- a + b
})
print("Vectorized result:")
print(c)
print(paste("Vectorized time (seconds):", vector_time["elapsed"]))
The first method uses a for loop to perform element-wise addition. The second method uses vectorized addition (c <- a + b).
Output:
[1] "Loop-based result:" [1] 11 22 33 44 55 [1] "Loop-based time (seconds): 0.0640000000000001" [1] "Vectorized result:" [1] 11 22 33 44 55 [1] "Vectorized time (seconds): 0"
Applying Functions to Vectors
R’s built-in functions are vectorized and work on entire vectors at once. No explicit loops are needed. Examples include sqrt(), log(), and exp().
- sqrt(x) – Square root of elements
- log(x), log10(x), log2(x) – Logarithm functions
- exp(x) – Exponential function
# Define a vector
x <- c(4, 9, 16, 25)
# Loop-based square root computation
normal_time <- system.time({
sqrt_loop <- numeric(length(x))
for (i in seq_along(x)) {
sqrt_loop[i] <- sqrt(x[i])
}
})
print("Loop-based result:")
print(sqrt_loop)
print(paste("Loop-based time (seconds):", normal_time["elapsed"]))
# Vectorized square root computation
vector_time <- system.time({
sqrt_x <- sqrt(x)
})
print("Vectorized result:")
print(sqrt_x)
print(paste("Vectorized time (seconds):", vector_time["elapsed"]))
The first method computes square roots using a loop. The second method applies sqrt() directly to the entire vector.
Output:
[1] "Loop-based result:" [1] 2 3 4 5 [1] "Loop-based time (seconds): 0.0600000000000001" [1] "Vectorized result:" [1] 2 3 4 5 [1] "Vectorized time (seconds): 0"
Using apply() for Vectorization
The apply() function in R is vectorized. It works on matrices and data frames. It applies a function along rows or columns. This removes the need for loops.
- apply(X, MARGIN, FUN) – Apply a function to rows (MARGIN=1) or columns (MARGIN=2)
- lapply(X, FUN) – Apply a function to each element of a list, returning a list
- sapply(X, FUN) – Similar to lapply(), but simplifies the output to a vector or matrix
- tapply(X, INDEX, FUN) – Apply a function to subsets of a vector based on a factor
# Create a matrix
mat <- matrix(1:9, nrow=3, ncol=3)
# Loop-based row sums computation
normal_time <- system.time({
row_sums_loop <- numeric(nrow(mat))
for (i in 1:nrow(mat)) {
row_sums_loop[i] <- sum(mat[i, ])
}
})
print("Loop-based result:")
print(row_sums_loop)
print(paste("Loop-based time (seconds):", normal_time["elapsed"]))
# Vectorized row sums computation
vector_time <- system.time({
row_sums <- apply(mat, 1, sum)
})
print("Vectorized result:")
print(row_sums)
print(paste("Vectorized time (seconds):", vector_time["elapsed"]))
The first method uses a for loop to compute row sums by iterating through each row. The second method uses vectorization with apply() to do the same task more efficiently.
Output:
[1] "Loop-based result:" [1] 12 15 18 [1] "Loop-based time (seconds): 0.0610000000000001" [1] "Vectorized result:" [1] 12 15 18 [1] "Vectorized time (seconds): 0"
Vectorized Conditional Operations
Vectorized conditionals in R evaluate conditions. Functions like ifelse() apply logic to entire vectors. This simplifies conditional operations.
- ifelse(condition, value_if_true, value_if_false) – Vectorized if-else statement
- which(x > value) – Returns indices where the condition holds true
- any(x > value), all(x > value) – Checks if any or all elements satisfy a condition
# Define a numeric vector
x <- c(1, 2, 3, 4, 5)
# Loop-based conditional operation
normal_time <- system.time({
result_loop <- character(length(x))
for (i in seq_along(x)) {
result_loop[i] <- if (x[i] %% 2 == 0) "Even" else "Odd"
}
})
print("Loop-based result:")
print(result_loop)
print(paste("Loop-based time (seconds):", normal_time["elapsed"]))
# Vectorized conditional operation using ifelse()
vector_time <- system.time({
result <- ifelse(x %% 2 == 0, "Even", "Odd")
})
print("Vectorized result:")
print(result)
print(paste("Vectorized time (seconds):", vector_time["elapsed"]))
The loop-based method checks each element one by one. The vectorized method uses ifelse(). It applies the condition to the entire vector at once.
Output:
[1] "Loop-based result:" [1] "Odd" "Even" "Odd" "Even" "Odd" [1] "Loop-based time (seconds): 0.0620000000000001" [1] "Vectorized result:" [1] "Odd" "Even" "Odd" "Even" "Odd" [1] "Vectorized time (seconds): 0.013"
Conclusion
Vectorization in R is an important technique that makes operations faster. It works on whole vectors instead of going through each element individually. This speeds up execution and makes the code easier to read and maintain.
We showed how vectorization works in different cases. This includes arithmetic operations, using functions on vectors, applying functions with apply(), and checking conditions.
