0Pricing
R Academy · Lección

Vectorización para acelerar el código

Reemplace los bucles explícitos por operaciones vectorizadas para obtener grandes mejoras de velocidad.

Vectorización para acelerar el código es una lección gratuita de R Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de R Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de R Academy incluye 4 lecciones en total.

Por qué es importante la vectorización

R es un lenguaje interpretado, por lo que los bucles for generan sobrecarga en cada iteración: despacho de llamadas a funciones, comprobación de límites y coerción de tipos. Las operaciones vectorizadas trasladan ese trabajo a código C compilado, que se ejecuta varios órdenes de magnitud más rápido.

La vectorización es la optimización más importante disponible en R base.

Ejemplo de bucle frente a cumsum()

Calcular un total acumulado con un bucle for frente a usar la función integrada cumsum() muestra claramente la diferencia. cumsum() llama a código compilado de nivel C y procesa todo el vector en una sola pasada.

n <- 500000
x <- rnorm(n)

t_loop <- system.time({
  result <- numeric(n)
  result[1] <- x[1]
  for (i in 2:n) result[i] <- result[i-1] + x[i]
})['elapsed']

t_vec <- system.time({
  result2 <- cumsum(x)
})['elapsed']

cat('Loop  :', t_loop, 's
')
cat('cumsum:', t_vec, 's
')

ifelse() frente a for + if

ifelse(condition, yes, no) es una condicional vectorizada que evalúa la condición en todo un vector de una vez. Sustituye los bucles for + if que procesan los elementos uno por uno por una única pasada de nivel C.

n <- 300000
x <- rnorm(n)

t_loop <- system.time({
  result <- numeric(n)
  for (i in seq_len(n)) result[i] <- if (x[i] > 0) x[i] else -x[i]
})['elapsed']

t_vec <- system.time({
  result2 <- ifelse(x > 0, x, -x)
})['elapsed']

cat('for+if :', t_loop, 's
')
cat('ifelse :', t_vec, 's
')

Preasignación de vectores de resultados

Cuando no se puede evitar un bucle, preasigne el vector de resultados antes del bucle. Hacer crecer un vector con c(result, new_val) dentro de un bucle copia el vector completo en cada iteración, lo que supone O(n^2) operaciones totales de memoria.

n <- 20000

t_grow <- system.time({
  result <- c()
  for (i in seq_len(n)) result <- c(result, i^2)
})['elapsed']

t_prealloc <- system.time({
  result2 <- numeric(n)
  for (i in seq_len(n)) result2[i] <- i^2
})['elapsed']

cat('Growing vector:', t_grow, 's
')
cat('Pre-allocated :', t_prealloc, 's
')

Tipos correctos para la preasignación

Use el constructor tipado que corresponda a sus datos para evitar la coerción implícita durante la preasignación:

  • numeric(n) — números de coma flotante de doble precisión
  • integer(n) — números enteros
  • character(n) — cadenas vacías
  • logical(n) — valores FALSE
  • vector('list', n) — lista de valores NULL
n <- 5
cat('numeric  :', numeric(n), '
')
cat('integer  :', integer(n), '
')
cat('logical  :', logical(n), '
')
cat('character:', character(n), '
')
cat('list len :', length(vector('list', n)), '
')

colSums() y rowSums() frente a apply()

Para operaciones con matrices, colSums(m), rowSums(m), colMeans(m) y rowMeans(m) son rutinas de C altamente optimizadas. De forma constante, son más rápidas que apply(m, 1, sum), que despacha la función de R sum una vez por fila.

m <- matrix(rnorm(1000 * 2000), nrow = 1000)

t_apply <- system.time(apply(m, 2, sum))['elapsed']
t_colsums <- system.time(colSums(m))['elapsed']

cat('apply(m,2,sum):', t_apply, 's
')
cat('colSums(m)    :', t_colsums, 's
')

La aritmética vectorizada siempre es rápida

Las operaciones aritméticas básicas con vectores — +, -, *, /, ^, sqrt(), log(), exp() — están todas vectorizadas. Operan elemento por elemento en todo un vector mediante una única llamada a C. Prefiéralas siempre a los bucles.

x <- 1:1000000

t1 <- system.time(y <- x^2 + 2*x + 1)['elapsed']

t2 <- system.time({
  y2 <- numeric(length(x))
  for (i in seq_along(x)) y2[i] <- x[i]^2 + 2*x[i] + 1
})['elapsed']

cat('Vectorized:', t1, 's
')
cat('Loop      :', t2, 's
')

Subconjuntos lógicos en lugar de bucles

Filtrar un vector con una condición lógica está vectorizado. En lugar de recorrerlo y añadir elementos condicionalmente, cree un índice lógico y haga el subconjunto una sola vez; el código subyacente en C realiza una única pasada.

x <- rnorm(500000)

t_loop <- system.time({
  pos <- c()
  for (v in x) if (v > 0) pos <- c(pos, v)
})['elapsed']

t_vec <- system.time({
  pos2 <- x[x > 0]
})['elapsed']

cat('Loop filter:', t_loop, 's
')
cat('Logical idx:', t_vec, 's
')

which() y tabulate() para trabajar con índices

Cuando necesite las posiciones de los valores TRUE, which(condition) está vectorizado y es rápido. tabulate(bin_vector) cuenta las apariciones de enteros más rápido que table() en rangos densos de enteros.

x <- sample(1:10, 100000, replace = TRUE)

t_table    <- system.time(table(x))['elapsed']
t_tabulate <- system.time(tabulate(x, nbins = 10))['elapsed']

cat('table()   :', t_table, 's
')
cat('tabulate():', t_tabulate, 's
')

idx <- which(x == 5)
cat('Positions of 5: first 5 =', head(idx, 5), '
')

Cuándo los bucles siguen siendo aceptables

No todos los bucles son perjudiciales. Los bucles son aceptables cuando:

  • Cada iteración depende del resultado anterior (dependencia secuencial)
  • El número de iteraciones es pequeño (< 1000)
  • El cuerpo del bucle llama a una función compleja que no tiene una alternativa vectorizada

En estos casos, céntrese en preasignar memoria y evite aumentar estructuras dentro del bucle.

# Sequential dependency -- loop is correct here
fib <- function(n) {
  result <- integer(n)
  result[1] <- 1L
  if (n >= 2) result[2] <- 1L
  for (i in seq_len(n)[-c(1,2)]) result[i] <- result[i-1] + result[i-2]
  result
}
cat('Fibonacci:', fib(10), '
')

Resumen de la vectorización

Reglas clave para vectorizar código R rápido:

  • Use cumsum/cumprod/diff para acumulaciones secuenciales
  • Use ifelse() para condicionales elemento a elemento
  • Preasigne con numeric(n) / vector('list',n)
  • Use colSums/rowSums/colMeans/rowMeans en lugar de apply()
  • Los subconjuntos lógicos son mejores que los bucles de filtrado

Comprobación rápida: preasignación

¿Por qué aumentar un vector con result <- c(result, new_val) dentro de un bucle es tan lento cuando n es grande?

Repaso de la vectorización

La vectorización es la principal herramienta de R para mejorar el rendimiento:

  • Las funciones vectorizadas (cumsum, ifelse, operadores aritméticos) llaman a código C compilado y son entre 10 y 100 veces más rápidas que los bucles R equivalentes
  • Preasigne los contenedores de resultados antes de cualquier bucle inevitable para evitar copias O(n^2)
  • colSums/rowSums superan a apply() en las agregaciones de matrices
  • Los subconjuntos lógicos sustituyen a los bucles de filtrado de forma clara y rápida

Preguntas frecuentes

¿La lección «Vectorización para acelerar el código» es gratis?

Sí — el texto completo de «Vectorización para acelerar el código» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de R Academy, actualiza a CoddyKit PRO. El curso de R Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Vectorización para acelerar el código»?

Reemplace los bucles explícitos por operaciones vectorizadas para obtener grandes mejoras de velocidad. Practicas R Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar R Academy?

No se requiere experiencia previa. R Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Vectorización para acelerar el código»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de R Academy?

Sí. Cada lección de R Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. system.time() y proc.time()
  2. Análisis de rendimiento del código con Rprof y profvis
  3. Vectorización para acelerar el código
  4. Evaluación comparativa con microbenchmark
← Volver a R Academy